You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
326 lines
13 KiB
Java
326 lines
13 KiB
Java
package com.fox2code.mmm.markdown;
|
|
|
|
import android.annotation.SuppressLint;
|
|
import android.content.Intent;
|
|
import android.content.pm.PackageManager;
|
|
import android.content.res.ColorStateList;
|
|
import android.content.res.Configuration;
|
|
import android.content.res.Resources;
|
|
import android.graphics.Color;
|
|
import android.graphics.drawable.ColorDrawable;
|
|
import android.os.Build;
|
|
import android.os.Bundle;
|
|
import android.util.Log;
|
|
import android.view.View;
|
|
import android.view.ViewConfiguration;
|
|
import android.view.ViewGroup;
|
|
import android.view.ViewTreeObserver;
|
|
import android.view.WindowManager;
|
|
import android.widget.HorizontalScrollView;
|
|
import android.widget.LinearLayout;
|
|
import android.widget.ScrollView;
|
|
import android.widget.TextView;
|
|
import android.widget.Toast;
|
|
|
|
import androidx.annotation.Nullable;
|
|
import androidx.annotation.StringRes;
|
|
import androidx.core.graphics.ColorUtils;
|
|
|
|
import com.fox2code.mmm.Constants;
|
|
import com.fox2code.mmm.MainApplication;
|
|
import com.fox2code.mmm.R;
|
|
import com.fox2code.mmm.XHooks;
|
|
import com.fox2code.mmm.compat.CompatActivity;
|
|
import com.fox2code.mmm.compat.CompatDisplay;
|
|
import com.fox2code.mmm.utils.Http;
|
|
import com.fox2code.mmm.utils.IntentHelper;
|
|
import com.google.android.material.chip.Chip;
|
|
import com.google.android.material.chip.ChipGroup;
|
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
|
import com.topjohnwu.superuser.Shell;
|
|
import com.topjohnwu.superuser.internal.UiThreadHandler;
|
|
|
|
import java.io.IOException;
|
|
import java.nio.charset.StandardCharsets;
|
|
import java.util.HashMap;
|
|
|
|
import eightbitlab.com.blurview.BlurView;
|
|
import eightbitlab.com.blurview.RenderScriptBlur;
|
|
|
|
|
|
public class MarkdownActivity extends CompatActivity {
|
|
private static final String TAG = "MarkdownActivity";
|
|
private static final HashMap<String, String> redirects = new HashMap<>(4);
|
|
private static final String[] variants = new String[]{
|
|
"readme.md", "README.MD", ".github/README.md"
|
|
};
|
|
private BlurView chipHolder;
|
|
private TextView actionBarPadding;
|
|
private BlurView actionBarBlur;
|
|
private ColorDrawable anyBarBackground;
|
|
private ScrollView scrollView;
|
|
private LinearLayout md_layout;
|
|
|
|
private static byte[] getRawMarkdown(String url) throws IOException {
|
|
String newUrl = redirects.get(url);
|
|
if (newUrl != null && !newUrl.equals(url)) {
|
|
return Http.doHttpGet(newUrl, true);
|
|
}
|
|
try {
|
|
return Http.doHttpGet(url, true);
|
|
} catch (IOException e) {
|
|
// Workaround GitHub README.md case sensitivity issue
|
|
if (url.startsWith("https://raw.githubusercontent.com/") &&
|
|
url.endsWith("/README.md")) {
|
|
String prefix = url.substring(0, url.length() - 9);
|
|
for (String suffix : variants) {
|
|
newUrl = prefix + suffix;
|
|
try { // Try with lowercase version
|
|
byte[] rawMarkdown = Http.doHttpGet(prefix + suffix, true);
|
|
redirects.put(url, newUrl); // Avoid retries
|
|
return rawMarkdown;
|
|
} catch (IOException ignored) {
|
|
}
|
|
}
|
|
}
|
|
throw e;
|
|
}
|
|
}
|
|
|
|
@Override
|
|
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
|
super.onCreate(savedInstanceState);
|
|
this.setDisplayHomeAsUpEnabled(true);
|
|
Intent intent = this.getIntent();
|
|
if (!MainApplication.checkSecret(intent)) {
|
|
Log.e(TAG, "Impersonation detected!");
|
|
this.forceBackPressed();
|
|
return;
|
|
}
|
|
String url = intent.getExtras()
|
|
.getString(Constants.EXTRA_MARKDOWN_URL);
|
|
String title = intent.getExtras()
|
|
.getString(Constants.EXTRA_MARKDOWN_TITLE);
|
|
String config = intent.getExtras()
|
|
.getString(Constants.EXTRA_MARKDOWN_CONFIG);
|
|
boolean change_boot = intent.getExtras()
|
|
.getBoolean(Constants.EXTRA_MARKDOWN_CHANGE_BOOT);
|
|
boolean needs_ramdisk = intent.getExtras()
|
|
.getBoolean(Constants.EXTRA_MARKDOWN_NEEDS_RAMDISK);
|
|
int min_magisk = intent.getExtras()
|
|
.getInt(Constants.EXTRA_MARKDOWN_MIN_MAGISK);
|
|
int min_api = intent.getExtras()
|
|
.getInt(Constants.EXTRA_MARKDOWN_MIN_API);
|
|
int max_api = intent.getExtras()
|
|
.getInt(Constants.EXTRA_MARKDOWN_MAX_API);
|
|
if (title != null && !title.isEmpty()) {
|
|
this.setTitle(title);
|
|
}
|
|
setActionBarBackground(null);
|
|
this.getWindow().setFlags(
|
|
WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION,
|
|
WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
|
|
if (config != null && !config.isEmpty()) {
|
|
String configPkg = IntentHelper.getPackageOfConfig(config);
|
|
try {
|
|
XHooks.checkConfigTargetExists(this, configPkg, config);
|
|
this.setActionBarExtraMenuButton(R.drawable.ic_baseline_app_settings_alt_24, menu -> {
|
|
IntentHelper.openConfig(this, config);
|
|
return true;
|
|
});
|
|
} catch (PackageManager.NameNotFoundException e) {
|
|
Log.w(TAG, "Config package \"" +
|
|
configPkg + "\" missing for markdown view");
|
|
}
|
|
}
|
|
Log.i(TAG, "Url for markdown " + url);
|
|
setContentView(R.layout.markdown_view);
|
|
final ViewGroup markdownBackground = findViewById(R.id.markdownBackground);
|
|
final TextView textView = findViewById(R.id.markdownView);
|
|
this.chipHolder = findViewById(R.id.chip_holder);
|
|
this.anyBarBackground = new ColorDrawable(Color.TRANSPARENT);
|
|
this.actionBarPadding = findViewById(R.id.markdown_action_bar_padding);
|
|
this.actionBarBlur = findViewById(R.id.markdown_action_bar_blur);
|
|
this.scrollView = findViewById(R.id.scrollView2);
|
|
this.md_layout = findViewById(R.id.md_layout);
|
|
final TextView footer = findViewById(R.id.markdownFooter);
|
|
UiThreadHandler.handler.postDelayed(() -> // Fix footer height
|
|
footer.setMinHeight(this.getNavigationBarHeight()), 1L);
|
|
this.actionBarBlur.setBackground(this.anyBarBackground);
|
|
this.setupBlurView(this.chipHolder, markdownBackground, this.anyBarBackground);
|
|
this.setupBlurView(this.actionBarBlur, markdownBackground, this.anyBarBackground);
|
|
this.updateScreenInsets();
|
|
this.updateUI();
|
|
|
|
// Really bad created (MSG by Der_Googler)
|
|
if (MainApplication.isChipsDisabled()) {
|
|
this.chipHolder.setVisibility(View.GONE);
|
|
} else {
|
|
this.chipHolder.setPadding(0,0,0,this.getNavigationBarHeight());
|
|
// set "message" to null to disable dialog
|
|
this.setChip(change_boot,
|
|
getString(R.string.module_can_change_boot),
|
|
"This module may change the boot image");
|
|
this.setChip(needs_ramdisk,
|
|
getString(R.string.module_needs_ramdisk),
|
|
"This module need boot ramdisk to be installed");
|
|
this.setChip(min_magisk, "Min. Magisk \"" + min_magisk + "\"",
|
|
null);
|
|
this.setChip(min_api, "Min. Android " + min_api,
|
|
null);
|
|
this.setChip(max_api, "Max. Android " + max_api,
|
|
null);
|
|
}
|
|
|
|
new Thread(() -> {
|
|
try {
|
|
Log.d(TAG, "Downloading");
|
|
byte[] rawMarkdown = getRawMarkdown(url);
|
|
Log.d(TAG, "Encoding");
|
|
String markdown = new String(rawMarkdown, StandardCharsets.UTF_8);
|
|
Log.d(TAG, "Done!");
|
|
runOnUiThread(() -> {
|
|
findViewById(R.id.markdownFooter)
|
|
.setMinimumHeight(this.getNavigationBarHeight());
|
|
MainApplication.getINSTANCE().getMarkwon().setMarkdown(
|
|
textView, MarkdownUrlLinker.urlLinkify(markdown));
|
|
if (markdownBackground != null) {
|
|
markdownBackground.setClickable(true);
|
|
markdownBackground.setOnClickListener(v -> this.onBackPressed());
|
|
}
|
|
});
|
|
} catch (Exception e) {
|
|
Log.e(TAG, "Failed download", e);
|
|
runOnUiThread(() -> {
|
|
Toast.makeText(this, R.string.failed_download,
|
|
Toast.LENGTH_SHORT).show();
|
|
this.onBackPressed();
|
|
});
|
|
}
|
|
}, "Markdown load thread").start();
|
|
}
|
|
|
|
private void setupBlurView(BlurView view, ViewGroup setupWith, ColorDrawable background) {
|
|
view.setBackground(background);
|
|
view.setupWith(setupWith).setFrameClearDrawable(
|
|
this.getWindow().getDecorView().getBackground())
|
|
.setBlurAlgorithm(new RenderScriptBlur(this))
|
|
.setBlurRadius(4F).setBlurAutoUpdate(true)
|
|
.setHasFixedTransformationMatrix(true);
|
|
}
|
|
|
|
private void updateScreenInsets() {
|
|
this.runOnUiThread(() -> this.updateScreenInsets(
|
|
this.getResources().getConfiguration()));
|
|
}
|
|
|
|
private void updateScreenInsets(Configuration configuration) {
|
|
boolean landscape = configuration.orientation ==
|
|
Configuration.ORIENTATION_LANDSCAPE;
|
|
int bottomInset = (landscape ? 0 : this.getNavigationBarHeight());
|
|
int statusBarHeight = getStatusBarHeight();
|
|
int actionBarHeight = getActionBarHeight();
|
|
int combinedBarsHeight = statusBarHeight + actionBarHeight;
|
|
this.actionBarPadding.setMinHeight(combinedBarsHeight);
|
|
//this.actionBarBlur.invalidate();
|
|
}
|
|
|
|
private void updateUI() {
|
|
boolean isLightMode = this.isLightTheme();
|
|
int colorBackground;
|
|
try {
|
|
colorBackground = this.getColorCompat(
|
|
android.R.attr.windowBackground);
|
|
} catch (Resources.NotFoundException e) {
|
|
colorBackground = this.getColorCompat(isLightMode ?
|
|
R.color.white : R.color.black);
|
|
}
|
|
this.md_layout.setPadding(0,this.getActionBarHeight(this) + this.getStatusBarHeight(),0,this.getNavigationBarHeight() + 56);
|
|
if (MainApplication.isBlurEnabled()) {
|
|
this.actionBarBlur.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, this.getActionBarHeight(this) + this.getStatusBarHeight()));
|
|
this.chipHolder.setBlurEnabled(true);
|
|
this.anyBarBackground.setColor(ColorUtils
|
|
.setAlphaComponent(colorBackground, 0x02));
|
|
this.anyBarBackground.setColor(Color.TRANSPARENT);
|
|
this.actionBarBlur.setBlurEnabled(true);
|
|
} else {
|
|
this.chipHolder.setBlurEnabled(false);
|
|
this.chipHolder.setOverlayColor(Color.TRANSPARENT);
|
|
this.anyBarBackground.setColor(colorBackground);
|
|
this.actionBarBlur.setBlurEnabled(false);
|
|
this.actionBarBlur.setOverlayColor(Color.TRANSPARENT);
|
|
}
|
|
}
|
|
|
|
private void setChip(boolean bool, String title, String message) {
|
|
if (bool) {
|
|
this.makeChip(title, message);
|
|
}
|
|
}
|
|
|
|
private void setChip(int i, String title, String message) {
|
|
if (i != 0) {
|
|
this.makeChip(title, message);
|
|
}
|
|
}
|
|
|
|
private void makeChip(String title, String message) {
|
|
final ChipGroup chip_group_holder = findViewById(R.id.chip_group_holder);
|
|
Chip chip = new Chip(this);
|
|
chip.setText(title);
|
|
chip.setVisibility(View.VISIBLE);
|
|
if (message != null) {
|
|
chip.setOnClickListener(_view -> {
|
|
MaterialAlertDialogBuilder builder =
|
|
new MaterialAlertDialogBuilder(this);
|
|
|
|
builder
|
|
.setTitle(title)
|
|
.setMessage(message)
|
|
.setCancelable(true)
|
|
.setPositiveButton(R.string.ok, (x, y) -> x.dismiss()).show();
|
|
|
|
});
|
|
}
|
|
chip_group_holder.addView(chip);
|
|
}
|
|
|
|
private String parseAndroidVersion(int version) {
|
|
switch (version) {
|
|
case Build.VERSION_CODES.LOLLIPOP:
|
|
return "5.0";
|
|
case Build.VERSION_CODES.LOLLIPOP_MR1:
|
|
return "5.1";
|
|
case Build.VERSION_CODES.M:
|
|
return "6.0";
|
|
case Build.VERSION_CODES.N:
|
|
return "7.0";
|
|
case Build.VERSION_CODES.N_MR1:
|
|
return "7.1";
|
|
case Build.VERSION_CODES.O:
|
|
return "8.0";
|
|
case Build.VERSION_CODES.O_MR1:
|
|
return "8.1";
|
|
case Build.VERSION_CODES.P:
|
|
return "9.0 (P)";
|
|
case Build.VERSION_CODES.Q:
|
|
return "10 (Q)";
|
|
case Build.VERSION_CODES.R:
|
|
return "11 (R)";
|
|
case Build.VERSION_CODES.S:
|
|
return "12 (S)";
|
|
case Build.VERSION_CODES.S_V2:
|
|
return "12L";
|
|
default:
|
|
return "false";
|
|
}
|
|
}
|
|
|
|
@Override
|
|
protected void onResume() {
|
|
super.onResume();
|
|
View footer = findViewById(R.id.markdownFooter);
|
|
if (footer != null) footer.setMinimumHeight(this.getNavigationBarHeight());
|
|
}
|
|
}
|