2121
2222import androidx .annotation .NonNull ;
2323import androidx .annotation .Nullable ;
24+ import androidx .core .content .FileProvider ;
2425import androidx .webkit .WebResourceErrorCompat ;
2526import androidx .webkit .WebSettingsCompat ;
2627import androidx .webkit .WebViewClientCompat ;
3435import com .fox2code .mmm .XHooks ;
3536import com .fox2code .mmm .utils .Http ;
3637import com .fox2code .mmm .utils .IntentHelper ;
38+ import com .google .android .material .progressindicator .LinearProgressIndicator ;
3739
3840import org .json .JSONException ;
3941import org .json .JSONObject ;
4042
4143import java .io .ByteArrayInputStream ;
44+ import java .io .File ;
45+ import java .io .FileOutputStream ;
4246import java .io .IOException ;
4347import java .util .HashMap ;
4448
@@ -54,15 +58,19 @@ public final class AndroidacyActivity extends FoxActivity {
5458 }
5559 }
5660
61+ File moduleFile ;
5762 WebView webView ;
5863 TextView webViewNote ;
5964 AndroidacyWebAPI androidacyWebAPI ;
65+ LinearProgressIndicator progressIndicator ;
6066 boolean backOnResume ;
67+ boolean downloadMode ;
6168
6269 @ SuppressWarnings ("deprecation" )
6370 @ Override
6471 @ SuppressLint ({"SetJavaScriptEnabled" , "JavascriptInterface" , "RestrictedApi" })
6572 protected void onCreate (@ Nullable Bundle savedInstanceState ) {
73+ this .moduleFile = new File (this .getCacheDir (), "module.zip" );
6674 super .onCreate (savedInstanceState );
6775 Intent intent = this .getIntent ();
6876 Uri uri ;
@@ -119,6 +127,8 @@ protected void onCreate(@Nullable Bundle savedInstanceState) {
119127 }
120128 }
121129 }
130+ this .progressIndicator = this .findViewById (R .id .progress_bar );
131+ this .progressIndicator .setMax (100 );
122132 this .webView = this .findViewById (R .id .webView );
123133 this .webViewNote = this .findViewById (R .id .webViewNote );
124134 WebSettings webSettings = this .webView .getSettings ();
@@ -156,6 +166,7 @@ public boolean shouldOverrideUrlLoading(
156166 // Don't open non Androidacy urls inside WebView
157167 if (request .isForMainFrame () &&
158168 !AndroidacyUtil .isAndroidacyLink (request .getUrl ())) {
169+ if (downloadMode || backOnResume ) return true ;
159170 Log .i (TAG , "Exiting WebView " + // hideToken in case isAndroidacyLink fail.
160171 AndroidacyUtil .hideToken (request .getUrl ().toString ()));
161172 IntentHelper .openUri (view .getContext (), request .getUrl ().toString ());
@@ -185,6 +196,8 @@ public void onPageStarted(WebView view, String url, Bitmap favicon) {
185196 @ Override
186197 public void onPageFinished (WebView view , String url ) {
187198 webViewNote .setVisibility (View .GONE );
199+ progressIndicator .setVisibility (View .INVISIBLE );
200+ progressIndicator .setProgressCompat (0 , false );
188201 }
189202
190203 private void onReceivedError (String url , int errorCode ) {
@@ -247,9 +260,22 @@ public boolean onConsoleMessage(ConsoleMessage consoleMessage) {
247260 }
248261 return super .onConsoleMessage (consoleMessage );
249262 }
263+
264+ @ Override
265+ public void onProgressChanged (WebView view , int newProgress ) {
266+ if (downloadMode ) return ;
267+ if (newProgress != 100 && // Show progress bar
268+ progressIndicator .getVisibility () != View .VISIBLE )
269+ progressIndicator .setVisibility (View .VISIBLE );
270+ progressIndicator .setProgressCompat (newProgress , true );
271+ if (newProgress == 100 && // Hide progress bar
272+ progressIndicator .getVisibility () != View .INVISIBLE )
273+ progressIndicator .setVisibility (View .INVISIBLE );
274+ }
250275 });
251276 this .webView .setDownloadListener ((
252277 downloadUrl , userAgent , contentDisposition , mimetype , contentLength ) -> {
278+ if (this .downloadMode || this .isDownloadUrl (downloadUrl )) return ;
253279 if (AndroidacyUtil .isAndroidacyLink (downloadUrl ) && !this .backOnResume ) {
254280 AndroidacyWebAPI androidacyWebAPI = this .androidacyWebAPI ;
255281 if (androidacyWebAPI != null ) {
@@ -259,7 +285,7 @@ public boolean onConsoleMessage(ConsoleMessage consoleMessage) {
259285 return ;
260286 // Workaround Androidacy bug
261287 final String moduleId = moduleIdOfUrl (downloadUrl );
262- if (moduleId != null ) {
288+ if (moduleId != null && ! this . isFileUrl ( downloadUrl ) ) {
263289 webView .evaluateJavascript ("document.querySelector(" +
264290 "\" #download-form input[name=_token]\" ).value" ,
265291 result -> new Thread ("Androidacy popup workaround thread" ) {
@@ -354,10 +380,22 @@ private String moduleIdOfUrl(String url) {
354380 if (i == -1 ) i = url .length ();
355381 if (url .startsWith (prefix )) return url .substring (prefix .length (), i );
356382 }
383+ if (this .isFileUrl (url )) {
384+ int i = url .indexOf ("&module=" );
385+ if (i != -1 ) {
386+ int j = url .indexOf ('&' , i + 1 );
387+ if (j == -1 ) {
388+ return url .substring (i + 8 );
389+ } else {
390+ return url .substring (i + 8 , j );
391+ }
392+ }
393+ }
357394 return null ;
358395 }
359396
360397 private boolean isFileUrl (String url ) {
398+ if (url == null ) return false ;
361399 for (String prefix : new String []{
362400 "https://production-api.androidacy.com/magisk/file/" ,
363401 "https://staging-api.androidacy.com/magisk/file/"
@@ -367,18 +405,57 @@ private boolean isFileUrl(String url) {
367405 return false ;
368406 }
369407
408+ private boolean isDownloadUrl (String url ) {
409+ for (String prefix : new String []{
410+ "https://production-api.androidacy.com/magisk/download/" ,
411+ "https://staging-api.androidacy.com/magisk/download/"
412+ }) { // Make both staging and non staging act the same
413+ if (url .startsWith (prefix )) return true ;
414+ }
415+ return false ;
416+ }
417+
370418 private boolean megaIntercept (String pageUrl , String fileUrl ) {
371419 if (pageUrl == null || fileUrl == null ) return false ;
372420 if (this .isFileUrl (fileUrl )) {
373421 Log .d (TAG , "megaIntercept(" +
374422 AndroidacyUtil .hideToken (pageUrl ) + ", " +
375423 AndroidacyUtil .hideToken (fileUrl ) + ")" );
376- }
424+ } else return false ;
377425 final AndroidacyWebAPI androidacyWebAPI = this .androidacyWebAPI ;
378- final String moduleId = this .moduleIdOfUrl (pageUrl );
379- if (moduleId == null || !this .isFileUrl (fileUrl )) return false ;
426+ String moduleId = this .moduleIdOfUrl (fileUrl );
427+ if (moduleId == null ) moduleId = this .moduleIdOfUrl (pageUrl );
428+ if (moduleId == null ) {
429+ Log .d (TAG , "No module id?" );
430+ return false ;
431+ }
380432 androidacyWebAPI .openNativeModuleDialogRaw (fileUrl ,
381433 moduleId , "" , androidacyWebAPI .canInstall ());
382434 return true ;
383435 }
436+
437+ Uri downloadFileAsync (String url ) throws IOException {
438+ this .downloadMode = true ;
439+ this .runOnUiThread (() -> {
440+ progressIndicator .setIndeterminate (false );
441+ progressIndicator .setVisibility (View .VISIBLE );
442+ });
443+ byte [] module ;
444+ try {
445+ module = Http .doHttpGet (url , (downloaded , total , done ) ->
446+ progressIndicator .setProgressCompat ((downloaded * 100 ) / total , true ));
447+ try (FileOutputStream fileOutputStream = new FileOutputStream (this .moduleFile )) {
448+ fileOutputStream .write (module );
449+ }
450+ } finally {
451+ module = null ;
452+ this .runOnUiThread (() ->
453+ progressIndicator .setVisibility (View .INVISIBLE ));
454+ }
455+ this .backOnResume = true ;
456+ this .downloadMode = false ;
457+ return FileProvider .getUriForFile (this ,
458+ this .getPackageName () + ".file-provider" ,
459+ this .moduleFile );
460+ }
384461}
0 commit comments