(fix) misc fixes

also ensure ui consistency

Signed-off-by: androidacy-user <opensource@androidacy.com>
master
androidacy-user 1 year ago
parent f2d36547c9
commit 3b115044b7

@ -1,6 +1,6 @@
package com.fox2code.mmm; package com.fox2code.mmm;
import static com.fox2code.mmm.MainApplication.isOfficial; import static com.fox2code.mmm.MainApplication.Iof;
import static com.fox2code.mmm.manager.ModuleInfo.FLAG_MM_REMOTE_MODULE; import static com.fox2code.mmm.manager.ModuleInfo.FLAG_MM_REMOTE_MODULE;
import android.Manifest; import android.Manifest;
@ -55,10 +55,8 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.google.android.material.progressindicator.LinearProgressIndicator; import com.google.android.material.progressindicator.LinearProgressIndicator;
import com.google.android.material.snackbar.Snackbar; import com.google.android.material.snackbar.Snackbar;
import org.chromium.net.CronetEngine;
import org.matomo.sdk.extra.TrackHelper; import org.matomo.sdk.extra.TrackHelper;
import java.net.URL;
import java.util.Objects; import java.util.Objects;
import io.realm.Realm; import io.realm.Realm;
@ -85,7 +83,6 @@ public class MainActivity extends FoxActivity implements SwipeRefreshLayout.OnRe
private CardView searchCard; private CardView searchCard;
private SearchView searchView; private SearchView searchView;
private boolean initMode; private boolean initMode;
private boolean urlFactoryInstalled = false;
public MainActivity() { public MainActivity() {
this.moduleViewListBuilder = new ModuleViewListBuilder(this); this.moduleViewListBuilder = new ModuleViewListBuilder(this);
@ -103,16 +100,6 @@ public class MainActivity extends FoxActivity implements SwipeRefreshLayout.OnRe
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
this.initMode = true; this.initMode = true;
// Ensure HTTP Cache directories are created
Http.ensureCacheDirs(this);
if (!urlFactoryInstalled) {
urlFactoryInstalled = true;
try {
URL.setURLStreamHandlerFactory(new CronetEngine.Builder(this).build().createURLStreamHandlerFactory());
} catch (Error ignored) {
// Ignore
}
}
if (doSetupRestarting) { if (doSetupRestarting) {
doSetupRestarting = false; doSetupRestarting = false;
} }
@ -120,7 +107,7 @@ public class MainActivity extends FoxActivity implements SwipeRefreshLayout.OnRe
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
TrackHelper.track().screen(this).with(MainApplication.getINSTANCE().getTracker()); TrackHelper.track().screen(this).with(MainApplication.getINSTANCE().getTracker());
// track enabled repos // track enabled repos
RealmConfiguration realmConfig = new RealmConfiguration.Builder().name("ReposList.realm").encryptionKey(MainApplication.getINSTANCE().getExistingKey()).directory(MainApplication.getINSTANCE().getDataDirWithPath("realms")).schemaVersion(1).allowQueriesOnUiThread(true).allowWritesOnUiThread(true).build(); RealmConfiguration realmConfig = new RealmConfiguration.Builder().name("ReposList.realm").encryptionKey(MainApplication.getINSTANCE().getKey()).directory(MainApplication.getINSTANCE().getDataDirWithPath("realms")).schemaVersion(1).allowQueriesOnUiThread(true).allowWritesOnUiThread(true).build();
Realm realm = Realm.getInstance(realmConfig); Realm realm = Realm.getInstance(realmConfig);
StringBuilder enabledRepos = new StringBuilder(); StringBuilder enabledRepos = new StringBuilder();
realm.executeTransaction(r -> { realm.executeTransaction(r -> {
@ -133,7 +120,7 @@ public class MainActivity extends FoxActivity implements SwipeRefreshLayout.OnRe
} }
TrackHelper.track().event("enabled_repos", enabledRepos.toString()).with(MainApplication.getINSTANCE().getTracker()); TrackHelper.track().event("enabled_repos", enabledRepos.toString()).with(MainApplication.getINSTANCE().getTracker());
// log all shared preferences that are present // log all shared preferences that are present
if (!isOfficial) { if (!Iof) {
Timber.w("You may be running an untrusted build."); Timber.w("You may be running an untrusted build.");
// Show a toast to warn the user // Show a toast to warn the user
Toast.makeText(this, R.string.not_official_build, Toast.LENGTH_LONG).show(); Toast.makeText(this, R.string.not_official_build, Toast.LENGTH_LONG).show();

@ -31,6 +31,7 @@ import com.fox2code.foxcompat.app.FoxApplication;
import com.fox2code.foxcompat.app.internal.FoxProcessExt; import com.fox2code.foxcompat.app.internal.FoxProcessExt;
import com.fox2code.foxcompat.view.FoxThemeWrapper; import com.fox2code.foxcompat.view.FoxThemeWrapper;
import com.fox2code.mmm.installer.InstallerInitializer; import com.fox2code.mmm.installer.InstallerInitializer;
import com.fox2code.mmm.utils.TimberUtils;
import com.fox2code.mmm.utils.io.GMSProviderInstaller; import com.fox2code.mmm.utils.io.GMSProviderInstaller;
import com.fox2code.mmm.utils.io.net.Http; import com.fox2code.mmm.utils.io.net.Http;
import com.fox2code.mmm.utils.sentry.SentryMain; import com.fox2code.mmm.utils.sentry.SentryMain;
@ -80,9 +81,6 @@ import io.noties.markwon.html.HtmlPlugin;
import io.noties.markwon.image.ImagesPlugin; import io.noties.markwon.image.ImagesPlugin;
import io.noties.markwon.image.network.OkHttpNetworkSchemeHandler; import io.noties.markwon.image.network.OkHttpNetworkSchemeHandler;
import io.realm.Realm; import io.realm.Realm;
import io.sentry.Sentry;
import io.sentry.SentryLevel;
import io.sentry.android.timber.SentryTimberTree;
import timber.log.Timber; import timber.log.Timber;
@SuppressWarnings("CommentedOutCode") @SuppressWarnings("CommentedOutCode")
@ -96,7 +94,7 @@ public class MainApplication extends FoxApplication implements androidx.work.Con
// Use FoxProcess wrapper helper. // Use FoxProcess wrapper helper.
private static final boolean wrapped = !FoxProcessExt.isRootLoader(); private static final boolean wrapped = !FoxProcessExt.isRootLoader();
private static final ArrayList<String> callers = new ArrayList<>(); private static final ArrayList<String> callers = new ArrayList<>();
public static boolean isOfficial = false; public static boolean Iof = false;
private static String SHOWCASE_MODE_TRUE = null; private static String SHOWCASE_MODE_TRUE = null;
private static long secret; private static long secret;
private static Locale timeFormatLocale = Resources.getSystem().getConfiguration().getLocales().get(0); private static Locale timeFormatLocale = Resources.getSystem().getConfiguration().getLocales().get(0);
@ -125,6 +123,7 @@ public class MainApplication extends FoxApplication implements androidx.work.Con
private Markwon markwon; private Markwon markwon;
private byte[] existingKey; private byte[] existingKey;
private Tracker tracker; private Tracker tracker;
private boolean makingNewKey = false;
public MainApplication() { public MainApplication() {
if (INSTANCE != null && INSTANCE != this) if (INSTANCE != null && INSTANCE != this)
@ -406,20 +405,13 @@ public class MainApplication extends FoxApplication implements androidx.work.Con
relPackageName = this.getPackageName(); relPackageName = this.getPackageName();
super.onCreate(); super.onCreate();
SentryMain.initialize(this); SentryMain.initialize(this);
// init timber // dirty workaround so timber doesn't bitch at us
if (BuildConfig.DEBUG) { TimberUtils.configTimber();
Timber.plant(new Timber.DebugTree());
} else {
if (isCrashReportingEnabled()) {
//noinspection UnstableApiUsage
Timber.plant(new SentryTimberTree(Sentry.getCurrentHub(), SentryLevel.ERROR, SentryLevel.ERROR));
} else {
Timber.plant(new ReleaseTree());
}
}
Timber.i("Starting FoxMMM version %s (%d) - commit %s", BuildConfig.VERSION_NAME, BuildConfig.VERSION_CODE, BuildConfig.COMMIT_HASH); Timber.i("Starting FoxMMM version %s (%d) - commit %s", BuildConfig.VERSION_NAME, BuildConfig.VERSION_CODE, BuildConfig.COMMIT_HASH);
// Update SSL Ciphers if update is possible // Update SSL Ciphers if update is possible
GMSProviderInstaller.installIfNeeded(this); GMSProviderInstaller.installIfNeeded(this);
Http.ensureCacheDirs();
Http.ensureURLHandler(this);
Timber.d("Initializing FoxMMM"); Timber.d("Initializing FoxMMM");
Timber.d("Started from background: %s", !isInForeground()); Timber.d("Started from background: %s", !isInForeground());
Timber.d("FoxMMM is running in debug mode"); Timber.d("FoxMMM is running in debug mode");
@ -451,17 +443,16 @@ public class MainApplication extends FoxApplication implements androidx.work.Con
} else { } else {
Timber.d("Matomo already has install"); Timber.d("Matomo already has install");
} }
// Determine if this is an official build based on the signature
try { try {
// Get the signature of the key used to sign the app
@SuppressLint("PackageManagerGetSignatures") Signature[] s = this.getPackageManager().getPackageInfo(this.getPackageName(), PackageManager.GET_SIGNATURES).signatures; @SuppressLint("PackageManagerGetSignatures") Signature[] s = this.getPackageManager().getPackageInfo(this.getPackageName(), PackageManager.GET_SIGNATURES).signatures;
@SuppressWarnings("SpellCheckingInspection") String[] osh = new String[]{"7bec7c4462f4aac616612d9f56a023ee3046e83afa956463b5fab547fd0a0be6", "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"}; @SuppressWarnings("SpellCheckingInspection") String[] osh = new String[]{"7bec7c4462f4aac616612d9f56a023ee3046e83afa956463b5fab547fd0a0be6", "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"};
//noinspection SpellCheckingInspection
String oosh = Hashing.sha256().hashBytes(s[0].toByteArray()).toString(); String oosh = Hashing.sha256().hashBytes(s[0].toByteArray()).toString();
isOfficial = Arrays.asList(osh).contains(oosh); Iof = Arrays.asList(osh).contains(oosh);
} catch (PackageManager.NameNotFoundException ignored) { } catch (PackageManager.NameNotFoundException ignored) {
} }
// hide this behind a buildconfig flag for now, but crash the app if it's not an official build and not debug // hide this behind a buildconfig flag for now, but crash the app if it's not an official build and not debug
if (BuildConfig.ENABLE_PROTECTION && !isOfficial && !BuildConfig.DEBUG) { if (BuildConfig.ENABLE_PROTECTION && !Iof && !BuildConfig.DEBUG) {
throw new RuntimeException("This is not an official build of FoxMMM"); throw new RuntimeException("This is not an official build of FoxMMM");
} }
SharedPreferences sharedPreferences = MainApplication.getPreferences("mmm"); SharedPreferences sharedPreferences = MainApplication.getPreferences("mmm");
@ -606,11 +597,26 @@ public class MainApplication extends FoxApplication implements androidx.work.Con
} }
// Create a key to encrypt a realm and save it securely in the keystore // Create a key to encrypt a realm and save it securely in the keystore
public byte[] getNewKey() { public byte[] getKey() {
if (makingNewKey) {
// sleep until the key is made
while (makingNewKey) try {
//noinspection BusyWait
Thread.sleep(100);
} catch (InterruptedException ignored) {
// silence is bliss
}
}
// attempt to read the existingKey property
if (existingKey != null) {
return existingKey;
}
// check if we have a key already // check if we have a key already
SharedPreferences sharedPreferences = MainApplication.getPreferences("realm_key"); SharedPreferences sharedPreferences = MainApplication.getPreferences("realm_key");
if (sharedPreferences.contains("iv_and_encrypted_key")) { if (sharedPreferences.contains("iv_and_encrypted_key")) {
return getExistingKey(); return getExistingKey();
} else {
makingNewKey = true;
} }
// open a connection to the android keystore // open a connection to the android keystore
KeyStore keyStore; KeyStore keyStore;
@ -677,6 +683,7 @@ public class MainApplication extends FoxApplication implements androidx.work.Con
Timber.d("Created all keys successfully."); Timber.d("Created all keys successfully.");
MainApplication.getPreferences("realm_key").edit().putString("iv_and_encrypted_key", Base64.encodeToString(initializationVectorAndEncryptedKey, Base64.NO_WRAP)).apply(); MainApplication.getPreferences("realm_key").edit().putString("iv_and_encrypted_key", Base64.encodeToString(initializationVectorAndEncryptedKey, Base64.NO_WRAP)).apply();
Timber.d("Saved the encrypted key in shared preferences."); Timber.d("Saved the encrypted key in shared preferences.");
makingNewKey = false;
return realmKey; // pass to a realm configuration via encryptionKey() return realmKey; // pass to a realm configuration via encryptionKey()
} }
@ -747,7 +754,7 @@ public class MainApplication extends FoxApplication implements androidx.work.Con
updateModules = new ArrayList<>(); updateModules = new ArrayList<>();
} }
private static class ReleaseTree extends Timber.Tree { public static class ReleaseTree extends Timber.Tree {
@Override @Override
protected void log(int priority, String tag, @NonNull String message, Throwable t) { protected void log(int priority, String tag, @NonNull String message, Throwable t) {
// basically silently drop all logs below error, and write the rest to logcat // basically silently drop all logs below error, and write the rest to logcat

@ -174,7 +174,7 @@ public class SetupActivity extends FoxActivity implements LanguageActivity {
editor.putBoolean("pref_analytics_enabled", ((MaterialSwitch) Objects.requireNonNull(view.findViewById(R.id.setup_app_analytics))).isChecked()); editor.putBoolean("pref_analytics_enabled", ((MaterialSwitch) Objects.requireNonNull(view.findViewById(R.id.setup_app_analytics))).isChecked());
Timber.d("Saving preferences"); Timber.d("Saving preferences");
// Set the repos in the ReposList realm db // Set the repos in the ReposList realm db
RealmConfiguration realmConfig = new RealmConfiguration.Builder().name("ReposList.realm").encryptionKey(MainApplication.getINSTANCE().getExistingKey()).directory(MainApplication.getINSTANCE().getDataDirWithPath("realms")).schemaVersion(1).build(); RealmConfiguration realmConfig = new RealmConfiguration.Builder().name("ReposList.realm").encryptionKey(MainApplication.getINSTANCE().getKey()).directory(MainApplication.getINSTANCE().getDataDirWithPath("realms")).schemaVersion(1).build();
boolean androidacyRepo = ((MaterialSwitch) Objects.requireNonNull(view.findViewById(R.id.setup_androidacy_repo))).isChecked(); boolean androidacyRepo = ((MaterialSwitch) Objects.requireNonNull(view.findViewById(R.id.setup_androidacy_repo))).isChecked();
boolean magiskAltRepo = ((MaterialSwitch) Objects.requireNonNull(view.findViewById(R.id.setup_magisk_alt_repo))).isChecked(); boolean magiskAltRepo = ((MaterialSwitch) Objects.requireNonNull(view.findViewById(R.id.setup_magisk_alt_repo))).isChecked();
Realm realm = Realm.getInstance(realmConfig); Realm realm = Realm.getInstance(realmConfig);
@ -292,7 +292,7 @@ public class SetupActivity extends FoxActivity implements LanguageActivity {
long startTime = System.currentTimeMillis(); long startTime = System.currentTimeMillis();
// create encryption key // create encryption key
Timber.d("Creating encryption key"); Timber.d("Creating encryption key");
byte[] key = MainApplication.getINSTANCE().getNewKey(); byte[] key = MainApplication.getINSTANCE().getKey();
// create the realm database for ReposList // create the realm database for ReposList
// create the realm configuration // create the realm configuration
RealmConfiguration config = new RealmConfiguration.Builder().name("ReposList.realm").directory(MainApplication.getINSTANCE().getDataDirWithPath("realms")).schemaVersion(1).encryptionKey(key).build(); RealmConfiguration config = new RealmConfiguration.Builder().name("ReposList.realm").directory(MainApplication.getINSTANCE().getDataDirWithPath("realms")).schemaVersion(1).encryptionKey(key).build();

@ -37,8 +37,8 @@ import com.fox2code.mmm.utils.io.PropUtils;
import com.fox2code.mmm.utils.io.net.Http; import com.fox2code.mmm.utils.io.net.Http;
import com.fox2code.mmm.utils.sentry.SentryBreadcrumb; import com.fox2code.mmm.utils.sentry.SentryBreadcrumb;
import com.fox2code.mmm.utils.sentry.SentryMain; import com.fox2code.mmm.utils.sentry.SentryMain;
import com.google.android.material.bottomnavigation.BottomNavigationItemView;
import com.google.android.material.dialog.MaterialAlertDialogBuilder; import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton;
import com.google.android.material.progressindicator.LinearProgressIndicator; import com.google.android.material.progressindicator.LinearProgressIndicator;
import com.topjohnwu.superuser.CallbackList; import com.topjohnwu.superuser.CallbackList;
import com.topjohnwu.superuser.Shell; import com.topjohnwu.superuser.Shell;
@ -57,6 +57,7 @@ import java.io.InputStreamReader;
import java.io.OutputStream; import java.io.OutputStream;
import java.util.Enumeration; import java.util.Enumeration;
import java.util.HashSet; import java.util.HashSet;
import java.util.Objects;
import java.util.zip.ZipEntry; import java.util.zip.ZipEntry;
import timber.log.Timber; import timber.log.Timber;
@ -64,7 +65,8 @@ import timber.log.Timber;
public class InstallerActivity extends FoxActivity { public class InstallerActivity extends FoxActivity {
private static final HashSet<String> extracted = new HashSet<>(); private static final HashSet<String> extracted = new HashSet<>();
public LinearProgressIndicator progressIndicator; public LinearProgressIndicator progressIndicator;
public ExtendedFloatingActionButton rebootFloatingButton; public BottomNavigationItemView rebootFloatingButton;
public BottomNavigationItemView cancelFloatingButton;
public InstallerTerminal installerTerminal; public InstallerTerminal installerTerminal;
private File moduleCache; private File moduleCache;
private File toDelete; private File toDelete;
@ -102,7 +104,7 @@ public class InstallerActivity extends FoxActivity {
return; return;
} }
// ensure the intent is from our app, and is either a url or within our directory. replace all instances of .. and url encoded .. // ensure the intent is from our app, and is either a url or within our directory. replace all instances of .. and url encoded ..
target = intent.getStringExtra(Constants.EXTRA_INSTALL_PATH).trim().replaceAll("\\.\\.", "").replaceAll("%2e%2e", ""); target = Objects.requireNonNull(intent.getStringExtra(Constants.EXTRA_INSTALL_PATH)).trim().replaceAll("\\.\\.", "").replaceAll("%2e%2e", "");
if (target.isEmpty() || !target.startsWith(MainApplication.getINSTANCE().getDataDir().getAbsolutePath()) && !target.startsWith("https://")) { if (target.isEmpty() || !target.startsWith(MainApplication.getINSTANCE().getDataDir().getAbsolutePath()) && !target.startsWith("https://")) {
this.forceBackPressed(); this.forceBackPressed();
return; return;
@ -148,6 +150,7 @@ public class InstallerActivity extends FoxActivity {
RecyclerView installTerminal; RecyclerView installTerminal;
this.progressIndicator = findViewById(R.id.progress_bar); this.progressIndicator = findViewById(R.id.progress_bar);
this.rebootFloatingButton = findViewById(R.id.install_terminal_reboot_fab); this.rebootFloatingButton = findViewById(R.id.install_terminal_reboot_fab);
this.cancelFloatingButton = findViewById(R.id.back_installer);
this.installerTerminal = new InstallerTerminal(installTerminal = findViewById(R.id.install_terminal), this.isLightTheme(), foreground, mmtReborn); this.installerTerminal = new InstallerTerminal(installTerminal = findViewById(R.id.install_terminal), this.isLightTheme(), foreground, mmtReborn);
(horizontalScroller != null ? horizontalScroller : installTerminal).setBackground(new ColorDrawable(background)); (horizontalScroller != null ? horizontalScroller : installTerminal).setBackground(new ColorDrawable(background));
installTerminal.setItemAnimator(null); installTerminal.setItemAnimator(null);
@ -528,6 +531,8 @@ public class InstallerActivity extends FoxActivity {
} }
}); });
this.rebootFloatingButton.setVisibility(View.VISIBLE); this.rebootFloatingButton.setVisibility(View.VISIBLE);
// handle back button
this.cancelFloatingButton.setOnClickListener(_view -> this.finishAndRemoveTask());
if (message != null && !message.isEmpty()) this.installerTerminal.addLine(message); if (message != null && !message.isEmpty()) this.installerTerminal.addLine(message);
if (optionalLink != null && !optionalLink.isEmpty()) { if (optionalLink != null && !optionalLink.isEmpty()) {
this.setActionBarExtraMenuButton(ActionButtonType.supportIconForUrl(optionalLink), menu -> { this.setActionBarExtraMenuButton(ActionButtonType.supportIconForUrl(optionalLink), menu -> {
@ -618,25 +623,13 @@ public class InstallerActivity extends FoxActivity {
command = rawCommand; command = rawCommand;
} }
switch (command) { switch (command) {
case "useRecovery": case "useRecovery" -> this.useRecovery = true;
this.useRecovery = true; case "addLine" -> this.terminal.addLine(arg);
break; case "setLastLine" -> this.terminal.setLastLine(arg);
case "addLine": case "clearTerminal" -> this.terminal.clearTerminal();
this.terminal.addLine(arg); case "scrollUp" -> this.terminal.scrollUp();
break; case "scrollDown" -> this.terminal.scrollDown();
case "setLastLine": case "showLoading" -> {
this.terminal.setLastLine(arg);
break;
case "clearTerminal":
this.terminal.clearTerminal();
break;
case "scrollUp":
this.terminal.scrollUp();
break;
case "scrollDown":
this.terminal.scrollDown();
break;
case "showLoading":
this.isRecoveryBar = false; this.isRecoveryBar = false;
if (!arg.isEmpty()) { if (!arg.isEmpty()) {
try { try {
@ -661,26 +654,24 @@ public class InstallerActivity extends FoxActivity {
this.progressIndicator.setIndeterminate(true); this.progressIndicator.setIndeterminate(true);
} }
this.progressIndicator.setVisibility(View.VISIBLE); this.progressIndicator.setVisibility(View.VISIBLE);
break; }
case "setLoading": case "setLoading" -> {
this.isRecoveryBar = false; this.isRecoveryBar = false;
try { try {
this.progressIndicator.setProgressCompat(Short.parseShort(arg), true); this.progressIndicator.setProgressCompat(Short.parseShort(arg), true);
} catch (Exception ignored) { } catch (Exception ignored) {
} }
break; }
case "hideLoading": case "hideLoading" -> {
this.isRecoveryBar = false; this.isRecoveryBar = false;
this.progressIndicator.setVisibility(View.GONE); this.progressIndicator.setVisibility(View.GONE);
break; }
case "setSupportLink": case "setSupportLink" -> {
// Only set link if valid // Only set link if valid
if (arg.isEmpty() || (arg.startsWith("https://") && arg.indexOf('/', 8) > 8)) if (arg.isEmpty() || (arg.startsWith("https://") && arg.indexOf('/', 8) > 8))
this.supportLink = arg; this.supportLink = arg;
break; }
case "disableANSI": case "disableANSI" -> this.terminal.disableAnsi();
this.terminal.disableAnsi();
break;
} }
} }

@ -97,7 +97,7 @@ public final class ModuleManager extends SyncManager {
// if the dir name matches the module name, use it as the cache dir // if the dir name matches the module name, use it as the cache dir
File tempCacheRoot = new File(dir.toString()); File tempCacheRoot = new File(dir.toString());
Timber.d("Looking for cache in %s", tempCacheRoot); Timber.d("Looking for cache in %s", tempCacheRoot);
realmConfiguration = new RealmConfiguration.Builder().name("ModuleListCache.realm").encryptionKey(MainApplication.getINSTANCE().getExistingKey()).schemaVersion(1).deleteRealmIfMigrationNeeded().allowWritesOnUiThread(true).allowQueriesOnUiThread(true).directory(tempCacheRoot).build(); realmConfiguration = new RealmConfiguration.Builder().name("ModuleListCache.realm").encryptionKey(MainApplication.getINSTANCE().getKey()).schemaVersion(1).deleteRealmIfMigrationNeeded().allowWritesOnUiThread(true).allowQueriesOnUiThread(true).directory(tempCacheRoot).build();
Realm realm = Realm.getInstance(realmConfiguration); Realm realm = Realm.getInstance(realmConfiguration);
Timber.d("Looking for cache for %s out of %d", module, realm.where(ModuleListCache.class).count()); Timber.d("Looking for cache for %s out of %d", module, realm.where(ModuleListCache.class).count());
moduleListCache = realm.where(ModuleListCache.class).equalTo("codename", module).findFirst(); moduleListCache = realm.where(ModuleListCache.class).equalTo("codename", module).findFirst();

@ -30,7 +30,7 @@ public class CustomRepoManager {
if (MainApplication.getPreferences("mmm").getString("last_shown_setup", "").equals("")) { if (MainApplication.getPreferences("mmm").getString("last_shown_setup", "").equals("")) {
return; return;
} }
RealmConfiguration realmConfiguration = new RealmConfiguration.Builder().name("ReposList.realm").encryptionKey(MainApplication.getINSTANCE().getExistingKey()).allowQueriesOnUiThread(true).allowWritesOnUiThread(true).directory(MainApplication.getINSTANCE().getDataDirWithPath("realms")).schemaVersion(1).build(); RealmConfiguration realmConfiguration = new RealmConfiguration.Builder().name("ReposList.realm").encryptionKey(MainApplication.getINSTANCE().getKey()).allowQueriesOnUiThread(true).allowWritesOnUiThread(true).directory(MainApplication.getINSTANCE().getDataDirWithPath("realms")).schemaVersion(1).build();
Realm realm = Realm.getInstance(realmConfiguration); Realm realm = Realm.getInstance(realmConfiguration);
if (realm.isInTransaction()) { if (realm.isInTransaction()) {
realm.commitTransaction(); realm.commitTransaction();
@ -118,7 +118,7 @@ public class CustomRepoManager {
} catch (Exception e) { } catch (Exception e) {
submitModule = null; submitModule = null;
} }
RealmConfiguration realmConfiguration = new RealmConfiguration.Builder().name("ReposList.realm").encryptionKey(MainApplication.getINSTANCE().getExistingKey()).allowQueriesOnUiThread(true).allowWritesOnUiThread(true).directory(MainApplication.getINSTANCE().getDataDirWithPath("realms")).schemaVersion(1).build(); RealmConfiguration realmConfiguration = new RealmConfiguration.Builder().name("ReposList.realm").encryptionKey(MainApplication.getINSTANCE().getKey()).allowQueriesOnUiThread(true).allowWritesOnUiThread(true).directory(MainApplication.getINSTANCE().getDataDirWithPath("realms")).schemaVersion(1).build();
Realm realm = Realm.getInstance(realmConfiguration); Realm realm = Realm.getInstance(realmConfiguration);
int finalI = i; int finalI = i;
String finalWebsite = website; String finalWebsite = website;

@ -39,6 +39,7 @@ public class RepoData extends XRepo {
public final JSONObject supportedProperties = new JSONObject(); public final JSONObject supportedProperties = new JSONObject();
private final Object populateLock = new Object(); private final Object populateLock = new Object();
public String url; public String url;
public String id; public String id;
public File cacheRoot; public File cacheRoot;
public SharedPreferences cachedPreferences; public SharedPreferences cachedPreferences;
@ -106,7 +107,7 @@ public class RepoData extends XRepo {
this.defaultName = url; // Set url as default name this.defaultName = url; // Set url as default name
this.forceHide = AppUpdateManager.shouldForceHide(this.id); this.forceHide = AppUpdateManager.shouldForceHide(this.id);
// this.enable is set from the database // this.enable is set from the database
RealmConfiguration realmConfiguration = new RealmConfiguration.Builder().name("ReposList.realm").encryptionKey(MainApplication.getINSTANCE().getExistingKey()).allowQueriesOnUiThread(true).allowWritesOnUiThread(true).directory(MainApplication.getINSTANCE().getDataDirWithPath("realms")).schemaVersion(1).build(); RealmConfiguration realmConfiguration = new RealmConfiguration.Builder().name("ReposList.realm").encryptionKey(MainApplication.getINSTANCE().getKey()).allowQueriesOnUiThread(true).allowWritesOnUiThread(true).directory(MainApplication.getINSTANCE().getDataDirWithPath("realms")).schemaVersion(1).build();
Realm realm = Realm.getInstance(realmConfiguration); Realm realm = Realm.getInstance(realmConfiguration);
ReposList reposList = realm.where(ReposList.class).equalTo("id", this.id).findFirst(); ReposList reposList = realm.where(ReposList.class).equalTo("id", this.id).findFirst();
if (reposList == null) { if (reposList == null) {
@ -283,7 +284,7 @@ public class RepoData extends XRepo {
@Override @Override
public boolean isEnabled() { public boolean isEnabled() {
RealmConfiguration realmConfiguration2 = new RealmConfiguration.Builder().name("ReposList.realm").encryptionKey(MainApplication.getINSTANCE().getExistingKey()).allowQueriesOnUiThread(true).allowWritesOnUiThread(true).directory(MainApplication.getINSTANCE().getDataDirWithPath("realms")).schemaVersion(1).build(); RealmConfiguration realmConfiguration2 = new RealmConfiguration.Builder().name("ReposList.realm").encryptionKey(MainApplication.getINSTANCE().getKey()).allowQueriesOnUiThread(true).allowWritesOnUiThread(true).directory(MainApplication.getINSTANCE().getDataDirWithPath("realms")).schemaVersion(1).build();
Realm realm2 = Realm.getInstance(realmConfiguration2); Realm realm2 = Realm.getInstance(realmConfiguration2);
AtomicBoolean dbEnabled = new AtomicBoolean(false); AtomicBoolean dbEnabled = new AtomicBoolean(false);
realm2.executeTransaction(realm -> { realm2.executeTransaction(realm -> {
@ -307,7 +308,7 @@ public class RepoData extends XRepo {
public void setEnabled(boolean enabled) { public void setEnabled(boolean enabled) {
this.enabled = enabled && !this.forceHide; this.enabled = enabled && !this.forceHide;
// reposlist realm // reposlist realm
RealmConfiguration realmConfiguration2 = new RealmConfiguration.Builder().name("ReposList.realm").encryptionKey(MainApplication.getINSTANCE().getExistingKey()).allowQueriesOnUiThread(true).allowWritesOnUiThread(true).directory(MainApplication.getINSTANCE().getDataDirWithPath("realms")).schemaVersion(1).build(); RealmConfiguration realmConfiguration2 = new RealmConfiguration.Builder().name("ReposList.realm").encryptionKey(MainApplication.getINSTANCE().getKey()).allowQueriesOnUiThread(true).allowWritesOnUiThread(true).directory(MainApplication.getINSTANCE().getDataDirWithPath("realms")).schemaVersion(1).build();
Realm realm2 = Realm.getInstance(realmConfiguration2); Realm realm2 = Realm.getInstance(realmConfiguration2);
realm2.executeTransaction(realm -> { realm2.executeTransaction(realm -> {
ReposList reposList = realm.where(ReposList.class).equalTo("id", this.id).findFirst(); ReposList reposList = realm.where(ReposList.class).equalTo("id", this.id).findFirst();
@ -327,9 +328,10 @@ public class RepoData extends XRepo {
Timber.e("Repo ID is null"); Timber.e("Repo ID is null");
return; return;
} }
// if repo starts with repo_, it's always enabled bc custom repos can't be disabled without being deleted.
this.forceHide = AppUpdateManager.shouldForceHide(this.id); this.forceHide = AppUpdateManager.shouldForceHide(this.id);
// reposlist realm // reposlist realm
RealmConfiguration realmConfiguration2 = new RealmConfiguration.Builder().name("ReposList.realm").encryptionKey(MainApplication.getINSTANCE().getExistingKey()).allowQueriesOnUiThread(true).allowWritesOnUiThread(true).directory(MainApplication.getINSTANCE().getDataDirWithPath("realms")).schemaVersion(1).build(); RealmConfiguration realmConfiguration2 = new RealmConfiguration.Builder().name("ReposList.realm").encryptionKey(MainApplication.getINSTANCE().getKey()).allowQueriesOnUiThread(true).allowWritesOnUiThread(true).directory(MainApplication.getINSTANCE().getDataDirWithPath("realms")).schemaVersion(1).build();
Realm realm2 = Realm.getInstance(realmConfiguration2); Realm realm2 = Realm.getInstance(realmConfiguration2);
boolean dbEnabled = false; boolean dbEnabled = false;
try { try {
@ -386,12 +388,12 @@ public class RepoData extends XRepo {
// should update (lastUpdate > 15 minutes) // should update (lastUpdate > 15 minutes)
public boolean shouldUpdate() { public boolean shouldUpdate() {
Timber.d("Repo " + this.id + " should update check called"); Timber.d("Repo " + this.id + " should update check called");
RealmConfiguration realmConfiguration2 = new RealmConfiguration.Builder().name("ReposList.realm").encryptionKey(MainApplication.getINSTANCE().getExistingKey()).allowQueriesOnUiThread(true).allowWritesOnUiThread(true).directory(MainApplication.getINSTANCE().getDataDirWithPath("realms")).schemaVersion(1).build(); RealmConfiguration realmConfiguration2 = new RealmConfiguration.Builder().name("ReposList.realm").encryptionKey(MainApplication.getINSTANCE().getKey()).allowQueriesOnUiThread(true).allowWritesOnUiThread(true).directory(MainApplication.getINSTANCE().getDataDirWithPath("realms")).schemaVersion(1).build();
Realm realm2 = Realm.getInstance(realmConfiguration2); Realm realm2 = Realm.getInstance(realmConfiguration2);
ReposList repo = realm2.where(ReposList.class).equalTo("id", this.id).findFirst(); ReposList repo = realm2.where(ReposList.class).equalTo("id", this.id).findFirst();
// Make sure ModuleListCache for repoId is not null // Make sure ModuleListCache for repoId is not null
File cacheRoot = MainApplication.getINSTANCE().getDataDirWithPath("realms/repos/" + this.id); File cacheRoot = MainApplication.getINSTANCE().getDataDirWithPath("realms/repos/" + this.id);
RealmConfiguration realmConfiguration = new RealmConfiguration.Builder().name("ModuleListCache.realm").encryptionKey(MainApplication.getINSTANCE().getExistingKey()).schemaVersion(1).deleteRealmIfMigrationNeeded().allowWritesOnUiThread(true).allowQueriesOnUiThread(true).directory(cacheRoot).build(); RealmConfiguration realmConfiguration = new RealmConfiguration.Builder().name("ModuleListCache.realm").encryptionKey(MainApplication.getINSTANCE().getKey()).schemaVersion(1).deleteRealmIfMigrationNeeded().allowWritesOnUiThread(true).allowQueriesOnUiThread(true).directory(cacheRoot).build();
Realm realm = Realm.getInstance(realmConfiguration); Realm realm = Realm.getInstance(realmConfiguration);
RealmResults<ModuleListCache> moduleListCache = realm.where(ModuleListCache.class).equalTo("repoId", this.id).findAll(); RealmResults<ModuleListCache> moduleListCache = realm.where(ModuleListCache.class).equalTo("repoId", this.id).findAll();
if (repo != null) { if (repo != null) {

@ -48,11 +48,11 @@ public class RepoUpdater {
if (!this.repoData.shouldUpdate()) { if (!this.repoData.shouldUpdate()) {
Timber.d("Fetching index from cache for %s", this.repoData.id); Timber.d("Fetching index from cache for %s", this.repoData.id);
File cacheRoot = MainApplication.getINSTANCE().getDataDirWithPath("realms/repos/" + this.repoData.id); File cacheRoot = MainApplication.getINSTANCE().getDataDirWithPath("realms/repos/" + this.repoData.id);
RealmConfiguration realmConfiguration = new RealmConfiguration.Builder().name("ModuleListCache.realm").encryptionKey(MainApplication.getINSTANCE().getExistingKey()).schemaVersion(1).deleteRealmIfMigrationNeeded().allowWritesOnUiThread(true).allowQueriesOnUiThread(true).directory(cacheRoot).build(); RealmConfiguration realmConfiguration = new RealmConfiguration.Builder().name("ModuleListCache.realm").encryptionKey(MainApplication.getINSTANCE().getKey()).schemaVersion(1).deleteRealmIfMigrationNeeded().allowWritesOnUiThread(true).allowQueriesOnUiThread(true).directory(cacheRoot).build();
Realm realm = Realm.getInstance(realmConfiguration); Realm realm = Realm.getInstance(realmConfiguration);
RealmResults<ModuleListCache> results = realm.where(ModuleListCache.class).equalTo("repoId", this.repoData.id).findAll(); RealmResults<ModuleListCache> results = realm.where(ModuleListCache.class).equalTo("repoId", this.repoData.id).findAll();
// reposlist realm // reposlist realm
RealmConfiguration realmConfiguration2 = new RealmConfiguration.Builder().name("ReposList.realm").encryptionKey(MainApplication.getINSTANCE().getExistingKey()).allowQueriesOnUiThread(true).allowWritesOnUiThread(true).directory(MainApplication.getINSTANCE().getDataDirWithPath("realms")).schemaVersion(1).build(); RealmConfiguration realmConfiguration2 = new RealmConfiguration.Builder().name("ReposList.realm").encryptionKey(MainApplication.getINSTANCE().getKey()).allowQueriesOnUiThread(true).allowWritesOnUiThread(true).directory(MainApplication.getINSTANCE().getDataDirWithPath("realms")).schemaVersion(1).build();
Realm realm2 = Realm.getInstance(realmConfiguration2); Realm realm2 = Realm.getInstance(realmConfiguration2);
this.toUpdate = Collections.emptyList(); this.toUpdate = Collections.emptyList();
this.toApply = new HashSet<>(); this.toApply = new HashSet<>();
@ -121,7 +121,7 @@ public class RepoUpdater {
// use realm to insert to // use realm to insert to
// props avail: // props avail:
File cacheRoot = MainApplication.getINSTANCE().getDataDirWithPath("realms/repos/" + this.repoData.id); File cacheRoot = MainApplication.getINSTANCE().getDataDirWithPath("realms/repos/" + this.repoData.id);
RealmConfiguration realmConfiguration = new RealmConfiguration.Builder().name("ModuleListCache.realm").encryptionKey(MainApplication.getINSTANCE().getExistingKey()).schemaVersion(1).deleteRealmIfMigrationNeeded().allowWritesOnUiThread(true).allowQueriesOnUiThread(true).directory(cacheRoot).build(); RealmConfiguration realmConfiguration = new RealmConfiguration.Builder().name("ModuleListCache.realm").encryptionKey(MainApplication.getINSTANCE().getKey()).schemaVersion(1).deleteRealmIfMigrationNeeded().allowWritesOnUiThread(true).allowQueriesOnUiThread(true).directory(cacheRoot).build();
// array with module info default values // array with module info default values
// supported properties for a module // supported properties for a module
//id=<string> //id=<string>
@ -337,7 +337,7 @@ public class RepoUpdater {
Timber.w("Failed to get module info from %s with error %s", this.repoData.id, e.getMessage()); Timber.w("Failed to get module info from %s with error %s", this.repoData.id, e.getMessage());
} }
this.indexRaw = null; this.indexRaw = null;
RealmConfiguration realmConfiguration2 = new RealmConfiguration.Builder().name("ReposList.realm").encryptionKey(MainApplication.getINSTANCE().getExistingKey()).allowQueriesOnUiThread(true).allowWritesOnUiThread(true).directory(MainApplication.getINSTANCE().getDataDirWithPath("realms")).schemaVersion(1).build(); RealmConfiguration realmConfiguration2 = new RealmConfiguration.Builder().name("ReposList.realm").encryptionKey(MainApplication.getINSTANCE().getKey()).allowQueriesOnUiThread(true).allowWritesOnUiThread(true).directory(MainApplication.getINSTANCE().getDataDirWithPath("realms")).schemaVersion(1).build();
Realm realm2 = Realm.getInstance(realmConfiguration2); Realm realm2 = Realm.getInstance(realmConfiguration2);
if (realm2.isInTransaction()) { if (realm2.isInTransaction()) {
realm2.cancelTransaction(); realm2.cancelTransaction();

@ -835,7 +835,7 @@ public class SettingsActivity extends FoxActivity implements LanguageActivity {
String flavor = BuildConfig.FLAVOR; String flavor = BuildConfig.FLAVOR;
String type = BuildConfig.BUILD_TYPE; String type = BuildConfig.BUILD_TYPE;
// Set the summary of pref_pkg_info to something like default-debug v1.0 (123) (Official) // Set the summary of pref_pkg_info to something like default-debug v1.0 (123) (Official)
String pkgInfo = getString(R.string.pref_pkg_info_summary, flavor + "-" + type, BuildConfig.VERSION_NAME, BuildConfig.VERSION_CODE, MainApplication.isOfficial ? getString(R.string.official) : getString(R.string.unofficial)); String pkgInfo = getString(R.string.pref_pkg_info_summary, flavor + "-" + type, BuildConfig.VERSION_NAME, BuildConfig.VERSION_CODE, MainApplication.Iof ? getString(R.string.official) : getString(R.string.unofficial));
findPreference("pref_pkg_info").setSummary(pkgInfo); findPreference("pref_pkg_info").setSummary(pkgInfo);
// special easter egg :) // special easter egg :)
var ref = new Object() { var ref = new Object() {
@ -957,7 +957,7 @@ public class SettingsActivity extends FoxActivity implements LanguageActivity {
}); });
} }
// Get magisk_alt_repo enabled state from realm db // Get magisk_alt_repo enabled state from realm db
RealmConfiguration realmConfig = new RealmConfiguration.Builder().name("ReposList.realm").encryptionKey(MainApplication.getINSTANCE().getExistingKey()).allowQueriesOnUiThread(true).allowWritesOnUiThread(true).directory(MainApplication.getINSTANCE().getDataDirWithPath("realms")).schemaVersion(1).build(); RealmConfiguration realmConfig = new RealmConfiguration.Builder().name("ReposList.realm").encryptionKey(MainApplication.getINSTANCE().getKey()).allowQueriesOnUiThread(true).allowWritesOnUiThread(true).directory(MainApplication.getINSTANCE().getDataDirWithPath("realms")).schemaVersion(1).build();
Realm realm1 = Realm.getInstance(realmConfig); Realm realm1 = Realm.getInstance(realmConfig);
ReposList reposList = realm1.where(ReposList.class).equalTo("id", "magisk_alt_repo").findFirst(); ReposList reposList = realm1.where(ReposList.class).equalTo("id", "magisk_alt_repo").findFirst();
if (reposList != null) { if (reposList != null) {
@ -994,7 +994,7 @@ public class SettingsActivity extends FoxActivity implements LanguageActivity {
SwitchPreferenceCompat switchPreferenceCompat = (SwitchPreferenceCompat) androidacyRepoEnabled; SwitchPreferenceCompat switchPreferenceCompat = (SwitchPreferenceCompat) androidacyRepoEnabled;
switchPreferenceCompat.setChecked(false); switchPreferenceCompat.setChecked(false);
// Disable in realm db // Disable in realm db
RealmConfiguration realmConfiguration = new RealmConfiguration.Builder().name("ReposList.realm").encryptionKey(MainApplication.getINSTANCE().getExistingKey()).allowQueriesOnUiThread(true).allowWritesOnUiThread(true).directory(MainApplication.getINSTANCE().getDataDirWithPath("realms")).schemaVersion(1).build(); RealmConfiguration realmConfiguration = new RealmConfiguration.Builder().name("ReposList.realm").encryptionKey(MainApplication.getINSTANCE().getKey()).allowQueriesOnUiThread(true).allowWritesOnUiThread(true).directory(MainApplication.getINSTANCE().getDataDirWithPath("realms")).schemaVersion(1).build();
Realm realm = Realm.getInstance(realmConfiguration); Realm realm = Realm.getInstance(realmConfiguration);
realm.executeTransaction(realm2 -> { realm.executeTransaction(realm2 -> {
ReposList repoRealmResults = realm2.where(ReposList.class).equalTo("id", "androidacy_repo").findFirst(); ReposList repoRealmResults = realm2.where(ReposList.class).equalTo("id", "androidacy_repo").findFirst();
@ -1007,7 +1007,7 @@ public class SettingsActivity extends FoxActivity implements LanguageActivity {
}); });
} }
// get if androidacy repo is enabled from realm db // get if androidacy repo is enabled from realm db
RealmConfiguration realmConfiguration = new RealmConfiguration.Builder().name("ReposList.realm").encryptionKey(MainApplication.getINSTANCE().getExistingKey()).allowQueriesOnUiThread(true).allowWritesOnUiThread(true).directory(MainApplication.getINSTANCE().getDataDirWithPath("realms")).schemaVersion(1).build(); RealmConfiguration realmConfiguration = new RealmConfiguration.Builder().name("ReposList.realm").encryptionKey(MainApplication.getINSTANCE().getKey()).allowQueriesOnUiThread(true).allowWritesOnUiThread(true).directory(MainApplication.getINSTANCE().getDataDirWithPath("realms")).schemaVersion(1).build();
Realm realm = Realm.getInstance(realmConfiguration); Realm realm = Realm.getInstance(realmConfiguration);
ReposList repoRealmResults = realm.where(ReposList.class).equalTo("id", "androidacy_repo").findFirst(); ReposList repoRealmResults = realm.where(ReposList.class).equalTo("id", "androidacy_repo").findFirst();
if (repoRealmResults == null) { if (repoRealmResults == null) {
@ -1164,7 +1164,7 @@ public class SettingsActivity extends FoxActivity implements LanguageActivity {
@SuppressLint("RestrictedApi") @SuppressLint("RestrictedApi")
public void updateCustomRepoList(boolean initial) { public void updateCustomRepoList(boolean initial) {
RealmConfiguration realmConfiguration = new RealmConfiguration.Builder().name("ReposList.realm").encryptionKey(MainApplication.getINSTANCE().getExistingKey()).allowQueriesOnUiThread(true).allowWritesOnUiThread(true).directory(MainApplication.getINSTANCE().getDataDirWithPath("realms")).schemaVersion(1).build(); RealmConfiguration realmConfiguration = new RealmConfiguration.Builder().name("ReposList.realm").encryptionKey(MainApplication.getINSTANCE().getKey()).allowQueriesOnUiThread(true).allowWritesOnUiThread(true).directory(MainApplication.getINSTANCE().getDataDirWithPath("realms")).schemaVersion(1).build();
Realm realm = Realm.getInstance(realmConfiguration); Realm realm = Realm.getInstance(realmConfiguration);
// get all repos that are not built-in // get all repos that are not built-in
int CUSTOM_REPO_ENTRIES = 0; int CUSTOM_REPO_ENTRIES = 0;
@ -1304,7 +1304,7 @@ public class SettingsActivity extends FoxActivity implements LanguageActivity {
if (preference == null) return; if (preference == null) return;
if (!preferenceName.contains("androidacy") && !preferenceName.contains("magisk_alt_repo")) { if (!preferenceName.contains("androidacy") && !preferenceName.contains("magisk_alt_repo")) {
if (repoData != null) { if (repoData != null) {
RealmConfiguration realmConfiguration = new RealmConfiguration.Builder().name("ReposList.realm").encryptionKey(MainApplication.getINSTANCE().getExistingKey()).allowQueriesOnUiThread(true).allowWritesOnUiThread(true).directory(MainApplication.getINSTANCE().getDataDirWithPath("realms")).schemaVersion(1).build(); RealmConfiguration realmConfiguration = new RealmConfiguration.Builder().name("ReposList.realm").encryptionKey(MainApplication.getINSTANCE().getKey()).allowQueriesOnUiThread(true).allowWritesOnUiThread(true).directory(MainApplication.getINSTANCE().getDataDirWithPath("realms")).schemaVersion(1).build();
Realm realm = Realm.getInstance(realmConfiguration); Realm realm = Realm.getInstance(realmConfiguration);
RealmResults<ReposList> repoDataRealmResults = realm.where(ReposList.class).equalTo("id", repoData.id).findAll(); RealmResults<ReposList> repoDataRealmResults = realm.where(ReposList.class).equalTo("id", repoData.id).findAll();
Timber.d("Setting preference " + preferenceName + " because it is not the Androidacy repo or the Magisk Alt Repo"); Timber.d("Setting preference " + preferenceName + " because it is not the Androidacy repo or the Magisk Alt Repo");

@ -0,0 +1,28 @@
package com.fox2code.mmm.utils
import com.fox2code.mmm.BuildConfig
import com.fox2code.mmm.MainApplication
import com.fox2code.mmm.MainApplication.ReleaseTree
import io.sentry.Sentry
import io.sentry.SentryLevel
import io.sentry.android.timber.SentryTimberTree
import timber.log.Timber
import timber.log.Timber.Forest.plant
@Suppress("UnstableApiUsage")
object TimberUtils {
@JvmStatic
fun configTimber() {
// init timber
// init timber
if (BuildConfig.DEBUG) {
plant(Timber.DebugTree())
} else {
if (MainApplication.isCrashReportingEnabled()) {
plant(SentryTimberTree(Sentry.getCurrentHub(), SentryLevel.ERROR, SentryLevel.ERROR))
} else {
plant(ReleaseTree())
}
}
}
}

@ -29,6 +29,7 @@ import com.fox2code.mmm.utils.io.Files;
import com.google.android.material.snackbar.Snackbar; import com.google.android.material.snackbar.Snackbar;
import com.google.net.cronet.okhttptransport.CronetInterceptor; import com.google.net.cronet.okhttptransport.CronetInterceptor;
import org.apache.commons.io.FileUtils;
import org.chromium.net.CronetEngine; import org.chromium.net.CronetEngine;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
@ -37,6 +38,7 @@ import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.net.InetAddress; import java.net.InetAddress;
import java.net.Proxy; import java.net.Proxy;
import java.net.URL;
import java.net.UnknownHostException; import java.net.UnknownHostException;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.ArrayList; import java.util.ArrayList;
@ -247,6 +249,8 @@ public enum Http {
doh = MainApplication.isDohEnabled(); doh = MainApplication.isDohEnabled();
} }
private static boolean urlFactoryInstalled;
private static OkHttpClient.Builder followRedirects(OkHttpClient.Builder builder, boolean followRedirects) { private static OkHttpClient.Builder followRedirects(OkHttpClient.Builder builder, boolean followRedirects) {
return builder.followRedirects(followRedirects).followSslRedirects(followRedirects); return builder.followRedirects(followRedirects).followSslRedirects(followRedirects);
} }
@ -411,50 +415,23 @@ public enum Http {
return hasWebView; return hasWebView;
} }
public static void ensureCacheDirs(MainActivity mainActivity) { public static void ensureCacheDirs() {
// Recursively ensure cache dirs for webview exist under our cache dir try {
File cacheDir = mainActivity.getCacheDir(); FileUtils.forceMkdir(new File((MainApplication.getINSTANCE().getDataDir() + "/cache/WebView/Default/HTTP Cache/Code Cache/wasm").replaceAll("//", "/")));
File webviewCacheDir = new File(cacheDir, "WebView"); FileUtils.forceMkdir(new File((MainApplication.getINSTANCE().getDataDir() + "/cache/WebView/Default/HTTP Cache/Code Cache/js").replaceAll("//", "/")));
if (!webviewCacheDir.exists()) { FileUtils.forceMkdir(new File((MainApplication.getINSTANCE().getDataDir() + "/cache/cronet").replaceAll("//", "/")));
if (!webviewCacheDir.mkdirs()) { } catch (IOException e) {
Timber.e("Failed to create webview cache dir"); Timber.e("Could not create cache dirs");
}
}
File webviewCacheDirCache = new File(webviewCacheDir, "Default");
if (!webviewCacheDirCache.exists()) {
if (!webviewCacheDirCache.mkdirs()) {
Timber.e("Failed to create webview cache dir");
}
}
File webviewCacheDirCacheCodeCache = new File(webviewCacheDirCache, "HTTP Cache");
if (!webviewCacheDirCacheCodeCache.exists()) {
if (!webviewCacheDirCacheCodeCache.mkdirs()) {
Timber.e("Failed to create webview cache dir");
}
}
File webviewCacheDirCacheCodeCacheIndex = new File(webviewCacheDirCacheCodeCache, "Code Cache");
if (!webviewCacheDirCacheCodeCacheIndex.exists()) {
if (!webviewCacheDirCacheCodeCacheIndex.mkdirs()) {
Timber.e("Failed to create webview cache dir");
}
}
File webviewCacheDirCacheCodeCacheIndexIndex = new File(webviewCacheDirCacheCodeCacheIndex, "Index");
if (!webviewCacheDirCacheCodeCacheIndexIndex.exists()) {
if (!webviewCacheDirCacheCodeCacheIndexIndex.mkdirs()) {
Timber.e("Failed to create webview cache dir");
}
}
// Create the js and wasm dirs
File webviewCacheDirCacheCodeCacheIndexIndexJs = new File(webviewCacheDirCacheCodeCache, "js");
if (!webviewCacheDirCacheCodeCacheIndexIndexJs.exists()) {
if (!webviewCacheDirCacheCodeCacheIndexIndexJs.mkdirs()) {
Timber.e("Failed to create webview cache dir");
}
} }
File webviewCacheDirCacheCodeCacheIndexIndexWasm = new File(webviewCacheDirCacheCodeCache, "wasm"); }
if (!webviewCacheDirCacheCodeCacheIndexIndexWasm.exists()) {
if (!webviewCacheDirCacheCodeCacheIndexIndexWasm.mkdirs()) { public static void ensureURLHandler(Context context) {
Timber.e("Failed to create webview cache dir"); if (!urlFactoryInstalled) {
try {
URL.setURLStreamHandlerFactory(new CronetEngine.Builder(context).build().createURLStreamHandlerFactory());
urlFactoryInstalled = true;
} catch (Error ignored) {
// Ignore
} }
} }
} }

@ -0,0 +1,5 @@
<vector android:autoMirrored="true" android:height="24dp"
android:tint="?attr/colorControlNormal" android:viewportHeight="24"
android:viewportWidth="24" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M20,11H7.83l5.59,-5.59L12,4l-8,8 8,8 1.41,-1.41L7.83,13H20v-2z"/>
</vector>

@ -101,7 +101,8 @@
<com.google.android.material.textview.MaterialTextView <com.google.android.material.textview.MaterialTextView
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_margin="4dp" android:layout_marginHorizontal="4dp"
android:layout_marginVertical="12dp"
android:text="@string/repos" android:text="@string/repos"
android:textAppearance="@android:style/TextAppearance.Material.Headline" /> android:textAppearance="@android:style/TextAppearance.Material.Headline" />
@ -109,7 +110,7 @@
android:id="@+id/setup_androidacy_repo" android:id="@+id/setup_androidacy_repo"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_margin="4dp" android:layout_margin="5dp"
android:checked="false" android:checked="false"
android:key="pref_androidacy_repo_enabled" android:key="pref_androidacy_repo_enabled"
android:text="@string/setup_androidacy_repo" android:text="@string/setup_androidacy_repo"
@ -119,7 +120,7 @@
<com.google.android.material.textview.MaterialTextView <com.google.android.material.textview.MaterialTextView
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_margin="4dp" android:layout_margin="5dp"
android:drawableStart="@drawable/ic_baseline_info_24" android:drawableStart="@drawable/ic_baseline_info_24"
android:drawablePadding="8dp" android:drawablePadding="8dp"
android:text="@string/setup_androidacy_repo_summary" android:text="@string/setup_androidacy_repo_summary"
@ -155,7 +156,8 @@
<com.google.android.material.textview.MaterialTextView <com.google.android.material.textview.MaterialTextView
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_margin="4dp" android:layout_marginHorizontal="4dp"
android:layout_marginVertical="12dp"
android:text="@string/pref_category_privacy" android:text="@string/pref_category_privacy"
android:textAppearance="@android:style/TextAppearance.Material.Headline" /> android:textAppearance="@android:style/TextAppearance.Material.Headline" />
@ -163,7 +165,7 @@
android:id="@+id/setup_crash_reporting" android:id="@+id/setup_crash_reporting"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_margin="4dp" android:layout_margin="5dp"
android:checked="false" android:checked="false"
android:key="pref_crash_reporting_enabled" android:key="pref_crash_reporting_enabled"
android:text="@string/setup_crash_reporting" android:text="@string/setup_crash_reporting"
@ -184,7 +186,7 @@
android:id="@+id/setup_crash_reporting_pii" android:id="@+id/setup_crash_reporting_pii"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_margin="4dp" android:layout_margin="5dp"
android:checked="false" android:checked="false"
android:key="pref_crash_reporting_pii" android:key="pref_crash_reporting_pii"
android:text="@string/setup_crash_reporting_pii" android:text="@string/setup_crash_reporting_pii"
@ -207,7 +209,7 @@
android:id="@+id/setup_app_analytics" android:id="@+id/setup_app_analytics"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_margin="4dp" android:layout_margin="5dp"
android:checked="false" android:checked="false"
android:key="pref_app_analytics" android:key="pref_app_analytics"
android:text="@string/setup_app_analytics" android:text="@string/setup_app_analytics"
@ -225,7 +227,8 @@
<com.google.android.material.textview.MaterialTextView <com.google.android.material.textview.MaterialTextView
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_margin="4dp" android:layout_marginHorizontal="4dp"
android:layout_marginVertical="12dp"
android:text="@string/setup_update_check_headline" android:text="@string/setup_update_check_headline"
android:textAppearance="@android:style/TextAppearance.Material.Headline" /> android:textAppearance="@android:style/TextAppearance.Material.Headline" />
@ -233,7 +236,7 @@
android:id="@+id/setup_background_update_check" android:id="@+id/setup_background_update_check"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_margin="4dp" android:layout_margin="5dp"
android:checked="false" android:checked="false"
android:key="pref_background_update_check" android:key="pref_background_update_check"
android:text="@string/setup_background_update_check" android:text="@string/setup_background_update_check"
@ -255,7 +258,7 @@
android:id="@+id/setup_background_update_check_require_wifi" android:id="@+id/setup_background_update_check_require_wifi"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_margin="4dp" android:layout_margin="5dp"
android:checked="true" android:checked="true"
android:key="pref_background_update_check_require_wifi" android:key="pref_background_update_check_require_wifi"
android:text="@string/setup_background_update_check_require_wifi" android:text="@string/setup_background_update_check_require_wifi"
@ -276,7 +279,8 @@
<com.google.android.material.textview.MaterialTextView <com.google.android.material.textview.MaterialTextView
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_margin="2dp" android:layout_marginHorizontal="4dp"
android:layout_marginVertical="12dp"
android:text="@string/other_section" android:text="@string/other_section"
android:textAppearance="@android:style/TextAppearance.Material.Headline" /> android:textAppearance="@android:style/TextAppearance.Material.Headline" />

@ -36,16 +36,10 @@
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" /> app:layout_constraintTop_toTopOf="parent" />
<com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton <com.google.android.material.bottomnavigation.BottomNavigationView
android:id="@+id/install_terminal_reboot_fab" android:layout_width="match_parent"
android:text="@string/install_terminal_reboot_now"
android:visibility="gone"
android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_margin="16dp" app:layout_constraintBottom_toBottomOf="parent"
android:textColor="@android:color/white" app:menu="@menu/bottom_nav_install" />
app:iconTint="@android:color/white"
app:icon="@drawable/ic_reboot_24"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintBottom_toBottomOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/back_installer"
android:icon="@drawable/baseline_arrow_back_24"
android:title="@string/back"
app:showAsAction="ifRoom" />
<item
android:id="@+id/install_terminal_reboot_fab"
android:icon="@drawable/ic_reboot_24"
android:title="@string/install_terminal_reboot_now"
app:showAsAction="ifRoom" />
<item
android:id="@+id/install_terminal_config"
android:icon="@drawable/ic_baseline_settings_24"
android:title="@string/config"
android:visible="false"
app:showAsAction="ifRoom" />
</menu>

@ -406,4 +406,5 @@
<string name="analytics_desc">Allow us to track app usage and installs. Fully GDPR compliant and uses Matomo, hosted by Androidacy.</string> <string name="analytics_desc">Allow us to track app usage and installs. Fully GDPR compliant and uses Matomo, hosted by Androidacy.</string>
<string name="debug_cat">Debugging</string> <string name="debug_cat">Debugging</string>
<string name="announcements">News and updates</string> <string name="announcements">News and updates</string>
<string name="back">Go back</string>
</resources> </resources>

Loading…
Cancel
Save