55import android .os .Looper ;
66import android .util .Log ;
77
8+ import androidx .annotation .NonNull ;
9+ import androidx .lifecycle .LiveData ;
10+ import androidx .lifecycle .Observer ;
11+ import androidx .work .Data ;
12+ import androidx .work .ExistingWorkPolicy ;
13+ import androidx .work .OneTimeWorkRequest ;
14+ import androidx .work .WorkInfo ;
15+ import androidx .work .WorkManager ;
16+ import androidx .work .Worker ;
17+ import androidx .work .WorkerParameters ;
18+
819import com .d4rk .androidtutorials .java .R ;
920
1021import org .commonmark .node .Node ;
1122import org .commonmark .parser .Parser ;
1223import org .commonmark .renderer .html .HtmlRenderer ;
1324
14- import java .io .BufferedReader ;
15- import java .io .InputStreamReader ;
16- import java .net .HttpURLConnection ;
17- import java .net .URL ;
1825import java .util .Objects ;
19- import java .util .concurrent .ExecutorService ;
20- import java .util .concurrent .Executors ;
26+ import java .util .concurrent .TimeUnit ;
2127import java .util .regex .Matcher ;
2228import java .util .regex .Pattern ;
2329
30+ import okhttp3 .ConnectionPool ;
31+ import okhttp3 .OkHttpClient ;
32+ import okhttp3 .Request ;
33+ import okhttp3 .Response ;
34+
35+ /**
36+ * Utility class for loading and parsing open source license data.
37+ */
2438public class OpenSourceLicensesUtils {
2539 private static final String TAG = "OpenSourceLicensesUtils" ;
26- private static final ExecutorService executor = Executors . newSingleThreadExecutor () ;
40+ private static final String WORK_NAME = "license_loader" ;
2741 private static final Handler mainHandler = new Handler (Looper .getMainLooper ());
42+ private static final OkHttpClient client = new OkHttpClient .Builder ()
43+ .connectionPool (new ConnectionPool (5 , 5 , TimeUnit .MINUTES ))
44+ .connectTimeout (10 , TimeUnit .SECONDS )
45+ .readTimeout (10 , TimeUnit .SECONDS )
46+ .build ();
47+
48+ public static void loadHtmlData (Context context , HtmlDataCallback callback ) {
49+ Context appContext = context .getApplicationContext ();
50+ WorkManager workManager = WorkManager .getInstance (appContext );
51+ OneTimeWorkRequest request = new OneTimeWorkRequest .Builder (LoadHtmlWorker .class )
52+ .addTag (WORK_NAME )
53+ .build ();
54+ workManager .enqueueUniqueWork (WORK_NAME , ExistingWorkPolicy .REPLACE , request );
55+ LiveData <WorkInfo > liveData = workManager .getWorkInfoByIdLiveData (request .getId ());
56+ Observer <WorkInfo > observer = new Observer <WorkInfo >() {
57+ @ Override
58+ public void onChanged (WorkInfo info ) {
59+ if (info != null && info .getState ().isFinished ()) {
60+ Data output = info .getOutputData ();
61+ final String changelogHtml = output .getString ("changelogHtml" );
62+ final String eulaHtml = output .getString ("eulaHtml" );
63+ mainHandler .post (() -> callback .onHtmlDataLoaded (changelogHtml , eulaHtml ));
64+ liveData .removeObserver (this );
65+ }
66+ }
67+ };
68+ liveData .observeForever (observer );
69+ }
70+
71+ static class LoadHtmlWorker extends Worker {
72+ LoadHtmlWorker (@ NonNull Context context , @ NonNull WorkerParameters params ) {
73+ super (context , params );
74+ }
2875
29- public static void loadHtmlData (final Context context , final HtmlDataCallback callback ) {
30- executor .execute (() -> {
76+ @ NonNull
77+ @ Override
78+ public Result doWork () {
79+ Context context = getApplicationContext ();
3180 String packageName = context .getPackageName ();
3281 String currentVersion = getAppVersion (context );
3382 String changelogUrl = "https://raw.githubusercontent.com/MihaiCristianCondrea/" + packageName + "/refs/heads/main/CHANGELOG.md" ;
@@ -40,58 +89,35 @@ public static void loadHtmlData(final Context context, final HtmlDataCallback ca
4089 String eulaMarkdown = loadMarkdown (context , eulaUrl , R .string .error_loading_eula );
4190 String eulaHtml = markdownToHtml (eulaMarkdown );
4291
43- mainHandler .post (() -> callback .onHtmlDataLoaded (changelogHtml , eulaHtml ));
44- });
92+ Data output = new Data .Builder ()
93+ .putString ("changelogHtml" , changelogHtml )
94+ .putString ("eulaHtml" , eulaHtml )
95+ .build ();
96+ return Result .success (output );
97+ }
4598 }
4699
47100 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 );
56-
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 ();
101+ Request request = new Request .Builder ().url (urlString ).build ();
102+ try (Response response = client .newCall (request ).execute ()) {
103+ if (response .isSuccessful () && response .body () != null ) {
104+ return response .body ().string ();
66105 } else {
67- Log .e (TAG , "Failed to load URL: " + urlString + " with response code: " + responseCode );
106+ Log .e (TAG , "Failed to load URL: " + urlString + " with response code: " + ( response != null ? response . code () : - 1 ) );
68107 return context .getString (errorStringId );
69108 }
70109 } catch (Exception e ) {
71110 Log .e (TAG , "Error loading markdown from URL: " + urlString , e );
72111 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- }
84112 }
85113 }
86114
87115 private static String extractLatestVersionChangelog (String markdown , String currentVersion ) {
88- // Define the regex pattern to match the latest version section
89116 String regexPattern = "(?m)^#\\ s+Version\\ s+" + Pattern .quote (currentVersion ) + ":\\ s*(.*?)^(#\\ s+Version\\ s+|$)" ;
90117 Pattern pattern = Pattern .compile (regexPattern , Pattern .DOTALL | Pattern .MULTILINE );
91118 Matcher matcher = pattern .matcher (markdown );
92119
93120 if (matcher .find ()) {
94- // Group 1 contains the changelog for the current version
95121 return Objects .requireNonNull (matcher .group (1 )).trim ();
96122 } else {
97123 Log .e (TAG , "No changelog available for version " + currentVersion );
@@ -113,11 +139,18 @@ private static String getAppVersion(Context context) {
113139 .versionName ;
114140 } catch (Exception e ) {
115141 Log .e (TAG , "Error getting app version" , e );
116- return "1.0.0" ; // Fallback version
142+ return "1.0.0" ;
117143 }
118144 }
119145
120146 public interface HtmlDataCallback {
121147 void onHtmlDataLoaded (String changelogHtml , String eulaHtml );
122148 }
123- }
149+
150+ public static void shutdown (Context context ) {
151+ WorkManager .getInstance (context ).cancelUniqueWork (WORK_NAME );
152+ client .dispatcher ().executorService ().shutdown ();
153+ client .connectionPool ().evictAll ();
154+ }
155+ }
156+
0 commit comments