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.
FoxMagiskModuleManager/app/src/main/java/com/fox2code/mmm/markdown/MarkdownActivity.java

247 lines
11 KiB
Java

package com.fox2code.mmm.markdown;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.graphics.Color;
import android.os.Build;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.Nullable;
import com.fox2code.foxcompat.app.FoxActivity;
import com.fox2code.mmm.Constants;
import com.fox2code.mmm.MainApplication;
import com.fox2code.mmm.R;
import com.fox2code.mmm.XHooks;
import com.fox2code.mmm.utils.IntentHelper;
import com.fox2code.mmm.utils.io.net.Http;
import com.google.android.material.bottomnavigation.BottomNavigationView;
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.internal.UiThreadHandler;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import timber.log.Timber;
public class MarkdownActivity extends FoxActivity {
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 TextView header;
private TextView footer;
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)) {
Timber.e("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, 0);
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) {
Timber.w("Config package \"" + configPkg + "\" missing for markdown view");
}
}
// validate the url won't crash the app
if (url == null || url.isEmpty() || url.contains("..")) {
Timber.e("Invalid url %s", String.valueOf(url));
this.forceBackPressed();
return;
}
//noinspection UnnecessaryCallToStringValueOf
Timber.i("Url for markdown %s", String.valueOf(url));
setContentView(R.layout.markdown_view);
final ViewGroup markdownBackground = findViewById(R.id.markdownBackground);
final TextView textView = findViewById(R.id.markdownView);
this.header = findViewById(R.id.markdownHeader);
this.footer = findViewById(R.id.markdownFooter);
this.updateBlurState();
UiThreadHandler.handler.post(() -> // Fix header/footer height
this.updateScreenInsets(this.getResources().getConfiguration()));
// Really bad created (MSG by Der_Googler)
// set "message" to null to disable dialog
if (change_boot) this.addChip(MarkdownChip.CHANGE_BOOT);
if (needs_ramdisk) this.addChip(MarkdownChip.NEED_RAMDISK);
if (min_magisk != 0) this.addChip(MarkdownChip.MIN_MAGISK, String.valueOf(min_magisk));
if (min_api != 0) this.addChip(MarkdownChip.MIN_SDK, parseAndroidVersion(min_api));
if (max_api != 0) this.addChip(MarkdownChip.MAX_SDK, parseAndroidVersion(max_api));
new Thread(() -> {
try {
Timber.i("Downloading");
byte[] rawMarkdown = getRawMarkdown(url);
Timber.i("Encoding");
String markdown = new String(rawMarkdown, StandardCharsets.UTF_8);
Timber.i("Done!");
runOnUiThread(() -> {
findViewById(R.id.markdownFooter).setMinimumHeight(this.getNavigationBarHeight());
MainApplication.getINSTANCE().getMarkwon().setMarkdown(textView, MarkdownUrlLinker.urlLinkify(markdown));
if (markdownBackground != null) {
markdownBackground.setClickable(true);
}
});
} catch (Exception e) {
Timber.e(e);
runOnUiThread(() -> Toast.makeText(this, R.string.failed_download, Toast.LENGTH_SHORT).show());
}
}, "Markdown load thread").start();
}
private void updateBlurState() {
if (MainApplication.isBlurEnabled()) {
// set bottom navigation bar color to transparent blur
BottomNavigationView bottomNavigationView = findViewById(R.id.bottom_navigation);
bottomNavigationView.setBackgroundColor(Color.TRANSPARENT);
bottomNavigationView.setAlpha(0.8F);
// set dialogs to have transparent blur
getWindow().addFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
}
}
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.header.setMinHeight(combinedBarsHeight);
this.footer.setMinHeight(bottomInset);
//this.actionBarBlur.invalidate();
}
@Override
public void refreshUI() {
super.refreshUI();
this.updateScreenInsets();
this.updateBlurState();
}
@Override
protected void onWindowUpdated() {
this.updateScreenInsets();
}
private void addChip(MarkdownChip markdownChip) {
this.makeChip(this.getString(markdownChip.title), markdownChip.desc == 0 ? null : this.getString(markdownChip.desc));
}
private void addChip(MarkdownChip markdownChip, String extra) {
String title = this.getString(markdownChip.title);
if (title.contains("%s")) {
title = title.replace("%s", extra);
} else {
title = title + " " + extra;
}
this.makeChip(title, markdownChip.desc == 0 ? null : this.getString(markdownChip.desc));
}
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) {
return switch (version) {
case Build.VERSION_CODES.JELLY_BEAN -> "4.1 JellyBean";
case Build.VERSION_CODES.JELLY_BEAN_MR1 -> "4.2 JellyBean";
case Build.VERSION_CODES.JELLY_BEAN_MR2 -> "4.3 JellyBean";
case Build.VERSION_CODES.KITKAT -> "4.4 KitKat";
case Build.VERSION_CODES.KITKAT_WATCH -> "4.4 KitKat Watch";
case Build.VERSION_CODES.LOLLIPOP -> "5.0 Lollipop";
case Build.VERSION_CODES.LOLLIPOP_MR1 -> "5.1 Lollipop";
case Build.VERSION_CODES.M -> "6.0 Marshmallow";
case Build.VERSION_CODES.N -> "7.0 Nougat";
case Build.VERSION_CODES.N_MR1 -> "7.1 Nougat";
case Build.VERSION_CODES.O -> "8.0 Oreo";
case Build.VERSION_CODES.O_MR1 -> "8.1 Oreo";
case Build.VERSION_CODES.P -> "9.0 Pie";
case Build.VERSION_CODES.Q -> "10 (Q)";
case Build.VERSION_CODES.R -> "11 (R)";
case Build.VERSION_CODES.S -> "12 (S)";
case Build.VERSION_CODES.S_V2 -> "12L";
case Build.VERSION_CODES.TIRAMISU -> "13 Tiramisu";
default -> "Sdk: " + version;
};
}
@Override
protected void onResume() {
super.onResume();
View footer = findViewById(R.id.markdownFooter);
if (footer != null) footer.setMinimumHeight(this.getNavigationBarHeight());
}
}