(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;
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 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.snackbar.Snackbar;
import org.chromium.net.CronetEngine;
import org.matomo.sdk.extra.TrackHelper;
import java.net.URL;
import java.util.Objects;
import io.realm.Realm;
@ -85,7 +83,6 @@ public class MainActivity extends FoxActivity implements SwipeRefreshLayout.OnRe
private CardView searchCard;
private SearchView searchView;
private boolean initMode;
private boolean urlFactoryInstalled = false;
public MainActivity() {
this.moduleViewListBuilder = new ModuleViewListBuilder(this);
@ -103,16 +100,6 @@ public class MainActivity extends FoxActivity implements SwipeRefreshLayout.OnRe
@Override
protected void onCreate(Bundle savedInstanceState) {
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) {
doSetupRestarting = false;
}
@ -120,7 +107,7 @@ public class MainActivity extends FoxActivity implements SwipeRefreshLayout.OnRe
super.onCreate(savedInstanceState);
TrackHelper.track().screen(this).with(MainApplication.getINSTANCE().getTracker());
// 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);
StringBuilder enabledRepos = new StringBuilder();
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());
// log all shared preferences that are present
if (!isOfficial) {
if (!Iof) {
Timber.w("You may be running an untrusted build.");
// Show a toast to warn the user
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.view.FoxThemeWrapper;
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.net.Http;
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.network.OkHttpNetworkSchemeHandler;
import io.realm.Realm;
import io.sentry.Sentry;
import io.sentry.SentryLevel;
import io.sentry.android.timber.SentryTimberTree;
import timber.log.Timber;
@SuppressWarnings("CommentedOutCode")
@ -96,7 +94,7 @@ public class MainApplication extends FoxApplication implements androidx.work.Con
// Use FoxProcess wrapper helper.
private static final boolean wrapped = !FoxProcessExt.isRootLoader();
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 long secret;
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 byte[] existingKey;
private Tracker tracker;
private boolean makingNewKey = false;
public MainApplication() {
if (INSTANCE != null && INSTANCE != this)
@ -406,20 +405,13 @@ public class MainApplication extends FoxApplication implements androidx.work.Con
relPackageName = this.getPackageName();
super.onCreate();
SentryMain.initialize(this);
// init timber
if (BuildConfig.DEBUG) {
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());
}
}
// dirty workaround so timber doesn't bitch at us
TimberUtils.configTimber();
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
GMSProviderInstaller.installIfNeeded(this);
Http.ensureCacheDirs();
Http.ensureURLHandler(this);
Timber.d("Initializing FoxMMM");
Timber.d("Started from background: %s", !isInForeground());
Timber.d("FoxMMM is running in debug mode");
@ -451,17 +443,16 @@ public class MainApplication extends FoxApplication implements androidx.work.Con
} else {
Timber.d("Matomo already has install");
}
// Determine if this is an official build based on the signature
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;
@SuppressWarnings("SpellCheckingInspection") String[] osh = new String[]{"7bec7c4462f4aac616612d9f56a023ee3046e83afa956463b5fab547fd0a0be6", "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"};
//noinspection SpellCheckingInspection
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) {
}
// 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");
}
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
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
SharedPreferences sharedPreferences = MainApplication.getPreferences("realm_key");
if (sharedPreferences.contains("iv_and_encrypted_key")) {
return getExistingKey();
} else {
makingNewKey = true;
}
// open a connection to the android keystore
KeyStore keyStore;
@ -677,6 +683,7 @@ public class MainApplication extends FoxApplication implements androidx.work.Con
Timber.d("Created all keys successfully.");
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.");
makingNewKey = false;
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<>();
}
private static class ReleaseTree extends Timber.Tree {
public static class ReleaseTree extends Timber.Tree {
@Override
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

@ -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());
Timber.d("Saving preferences");
// 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 magiskAltRepo = ((MaterialSwitch) Objects.requireNonNull(view.findViewById(R.id.setup_magisk_alt_repo))).isChecked();
Realm realm = Realm.getInstance(realmConfig);
@ -292,7 +292,7 @@ public class SetupActivity extends FoxActivity implements LanguageActivity {
long startTime = System.currentTimeMillis();
// create 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 configuration
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.sentry.SentryBreadcrumb;
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.floatingactionbutton.ExtendedFloatingActionButton;
import com.google.android.material.progressindicator.LinearProgressIndicator;
import com.topjohnwu.superuser.CallbackList;
import com.topjohnwu.superuser.Shell;
@ -57,6 +57,7 @@ import java.io.InputStreamReader;
import java.io.OutputStream;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Objects;
import java.util.zip.ZipEntry;
import timber.log.Timber;
@ -64,7 +65,8 @@ import timber.log.Timber;
public class InstallerActivity extends FoxActivity {
private static final HashSet<String> extracted = new HashSet<>();
public LinearProgressIndicator progressIndicator;
public ExtendedFloatingActionButton rebootFloatingButton;
public BottomNavigationItemView rebootFloatingButton;
public BottomNavigationItemView cancelFloatingButton;
public InstallerTerminal installerTerminal;
private File moduleCache;
private File toDelete;
@ -102,7 +104,7 @@ public class InstallerActivity extends FoxActivity {
return;
}
// 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://")) {
this.forceBackPressed();
return;
@ -148,6 +150,7 @@ public class InstallerActivity extends FoxActivity {
RecyclerView installTerminal;
this.progressIndicator = findViewById(R.id.progress_bar);
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);
(horizontalScroller != null ? horizontalScroller : installTerminal).setBackground(new ColorDrawable(background));
installTerminal.setItemAnimator(null);
@ -528,6 +531,8 @@ public class InstallerActivity extends FoxActivity {
}
});
this.rebootFloatingButton.setVisibility(View.VISIBLE);
// handle back button
this.cancelFloatingButton.setOnClickListener(_view -> this.finishAndRemoveTask());
if (message != null && !message.isEmpty()) this.installerTerminal.addLine(message);
if (optionalLink != null && !optionalLink.isEmpty()) {
this.setActionBarExtraMenuButton(ActionButtonType.supportIconForUrl(optionalLink), menu -> {
@ -618,25 +623,13 @@ public class InstallerActivity extends FoxActivity {
command = rawCommand;
}
switch (command) {
case "useRecovery":
this.useRecovery = true;
break;
case "addLine":
this.terminal.addLine(arg);
break;
case "setLastLine":
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":
case "useRecovery" -> this.useRecovery = true;
case "addLine" -> this.terminal.addLine(arg);
case "setLastLine" -> this.terminal.setLastLine(arg);
case "clearTerminal" -> this.terminal.clearTerminal();
case "scrollUp" -> this.terminal.scrollUp();
case "scrollDown" -> this.terminal.scrollDown();
case "showLoading" -> {
this.isRecoveryBar = false;
if (!arg.isEmpty()) {
try {
@ -661,26 +654,24 @@ public class InstallerActivity extends FoxActivity {
this.progressIndicator.setIndeterminate(true);
}
this.progressIndicator.setVisibility(View.VISIBLE);
break;
case "setLoading":
}
case "setLoading" -> {
this.isRecoveryBar = false;
try {
this.progressIndicator.setProgressCompat(Short.parseShort(arg), true);
} catch (Exception ignored) {
}
break;
case "hideLoading":
}
case "hideLoading" -> {
this.isRecoveryBar = false;
this.progressIndicator.setVisibility(View.GONE);
break;
case "setSupportLink":
}
case "setSupportLink" -> {
// Only set link if valid
if (arg.isEmpty() || (arg.startsWith("https://") && arg.indexOf('/', 8) > 8))
this.supportLink = arg;
break;
case "disableANSI":
this.terminal.disableAnsi();
break;
}
case "disableANSI" -> this.terminal.disableAnsi();
}
}

@ -97,7 +97,7 @@ public final class ModuleManager extends SyncManager {
// if the dir name matches the module name, use it as the cache dir
File tempCacheRoot = new File(dir.toString());
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);
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();

@ -30,7 +30,7 @@ public class CustomRepoManager {
if (MainApplication.getPreferences("mmm").getString("last_shown_setup", "").equals("")) {
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);
if (realm.isInTransaction()) {
realm.commitTransaction();
@ -118,7 +118,7 @@ public class CustomRepoManager {
} catch (Exception e) {
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);
int finalI = i;
String finalWebsite = website;

@ -39,6 +39,7 @@ public class RepoData extends XRepo {
public final JSONObject supportedProperties = new JSONObject();
private final Object populateLock = new Object();
public String url;
public String id;
public File cacheRoot;
public SharedPreferences cachedPreferences;
@ -106,7 +107,7 @@ public class RepoData extends XRepo {
this.defaultName = url; // Set url as default name
this.forceHide = AppUpdateManager.shouldForceHide(this.id);
// 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);
ReposList reposList = realm.where(ReposList.class).equalTo("id", this.id).findFirst();
if (reposList == null) {
@ -283,7 +284,7 @@ public class RepoData extends XRepo {
@Override
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);
AtomicBoolean dbEnabled = new AtomicBoolean(false);
realm2.executeTransaction(realm -> {
@ -307,7 +308,7 @@ public class RepoData extends XRepo {
public void setEnabled(boolean enabled) {
this.enabled = enabled && !this.forceHide;
// 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);
realm2.executeTransaction(realm -> {
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");
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);
// 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);
boolean dbEnabled = false;
try {
@ -386,12 +388,12 @@ public class RepoData extends XRepo {
// should update (lastUpdate > 15 minutes)
public boolean shouldUpdate() {
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);
ReposList repo = realm2.where(ReposList.class).equalTo("id", this.id).findFirst();
// Make sure ModuleListCache for repoId is not null
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);
RealmResults<ModuleListCache> moduleListCache = realm.where(ModuleListCache.class).equalTo("repoId", this.id).findAll();
if (repo != null) {

@ -48,11 +48,11 @@ public class RepoUpdater {
if (!this.repoData.shouldUpdate()) {
Timber.d("Fetching index from cache for %s", 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);
RealmResults<ModuleListCache> results = realm.where(ModuleListCache.class).equalTo("repoId", this.repoData.id).findAll();
// 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);
this.toUpdate = Collections.emptyList();
this.toApply = new HashSet<>();
@ -121,7 +121,7 @@ public class RepoUpdater {
// use realm to insert to
// props avail:
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
// supported properties for a module
//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());
}
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);
if (realm2.isInTransaction()) {
realm2.cancelTransaction();

@ -835,7 +835,7 @@ public class SettingsActivity extends FoxActivity implements LanguageActivity {
String flavor = BuildConfig.FLAVOR;
String type = BuildConfig.BUILD_TYPE;
// 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);
// special easter egg :)
var ref = new Object() {
@ -957,7 +957,7 @@ public class SettingsActivity extends FoxActivity implements LanguageActivity {
});
}
// 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);
ReposList reposList = realm1.where(ReposList.class).equalTo("id", "magisk_alt_repo").findFirst();
if (reposList != null) {
@ -994,7 +994,7 @@ public class SettingsActivity extends FoxActivity implements LanguageActivity {
SwitchPreferenceCompat switchPreferenceCompat = (SwitchPreferenceCompat) androidacyRepoEnabled;
switchPreferenceCompat.setChecked(false);
// 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.executeTransaction(realm2 -> {
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
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);
ReposList repoRealmResults = realm.where(ReposList.class).equalTo("id", "androidacy_repo").findFirst();
if (repoRealmResults == null) {
@ -1164,7 +1164,7 @@ public class SettingsActivity extends FoxActivity implements LanguageActivity {
@SuppressLint("RestrictedApi")
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);
// get all repos that are not built-in
int CUSTOM_REPO_ENTRIES = 0;
@ -1304,7 +1304,7 @@ public class SettingsActivity extends FoxActivity implements LanguageActivity {
if (preference == null) return;
if (!preferenceName.contains("androidacy") && !preferenceName.contains("magisk_alt_repo")) {
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);
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");

@ -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.net.cronet.okhttptransport.CronetInterceptor;
import org.apache.commons.io.FileUtils;
import org.chromium.net.CronetEngine;
import java.io.ByteArrayOutputStream;
@ -37,6 +38,7 @@ import java.io.IOException;
import java.io.InputStream;
import java.net.InetAddress;
import java.net.Proxy;
import java.net.URL;
import java.net.UnknownHostException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
@ -247,6 +249,8 @@ public enum Http {
doh = MainApplication.isDohEnabled();
}
private static boolean urlFactoryInstalled;
private static OkHttpClient.Builder followRedirects(OkHttpClient.Builder builder, boolean followRedirects) {
return builder.followRedirects(followRedirects).followSslRedirects(followRedirects);
}
@ -411,50 +415,23 @@ public enum Http {
return hasWebView;
}
public static void ensureCacheDirs(MainActivity mainActivity) {
// Recursively ensure cache dirs for webview exist under our cache dir
File cacheDir = mainActivity.getCacheDir();
File webviewCacheDir = new File(cacheDir, "WebView");
if (!webviewCacheDir.exists()) {
if (!webviewCacheDir.mkdirs()) {
Timber.e("Failed to create webview cache dir");
}
}
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");
}
public static void ensureCacheDirs() {
try {
FileUtils.forceMkdir(new File((MainApplication.getINSTANCE().getDataDir() + "/cache/WebView/Default/HTTP Cache/Code Cache/wasm").replaceAll("//", "/")));
FileUtils.forceMkdir(new File((MainApplication.getINSTANCE().getDataDir() + "/cache/WebView/Default/HTTP Cache/Code Cache/js").replaceAll("//", "/")));
FileUtils.forceMkdir(new File((MainApplication.getINSTANCE().getDataDir() + "/cache/cronet").replaceAll("//", "/")));
} catch (IOException e) {
Timber.e("Could not create cache dirs");
}
File webviewCacheDirCacheCodeCacheIndexIndexWasm = new File(webviewCacheDirCacheCodeCache, "wasm");
if (!webviewCacheDirCacheCodeCacheIndexIndexWasm.exists()) {
if (!webviewCacheDirCacheCodeCacheIndexIndexWasm.mkdirs()) {
Timber.e("Failed to create webview cache dir");
}
public static void ensureURLHandler(Context context) {
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
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="4dp"
android:layout_marginHorizontal="4dp"
android:layout_marginVertical="12dp"
android:text="@string/repos"
android:textAppearance="@android:style/TextAppearance.Material.Headline" />
@ -109,7 +110,7 @@
android:id="@+id/setup_androidacy_repo"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="4dp"
android:layout_margin="5dp"
android:checked="false"
android:key="pref_androidacy_repo_enabled"
android:text="@string/setup_androidacy_repo"
@ -119,7 +120,7 @@
<com.google.android.material.textview.MaterialTextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="4dp"
android:layout_margin="5dp"
android:drawableStart="@drawable/ic_baseline_info_24"
android:drawablePadding="8dp"
android:text="@string/setup_androidacy_repo_summary"
@ -155,7 +156,8 @@
<com.google.android.material.textview.MaterialTextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="4dp"
android:layout_marginHorizontal="4dp"
android:layout_marginVertical="12dp"
android:text="@string/pref_category_privacy"
android:textAppearance="@android:style/TextAppearance.Material.Headline" />
@ -163,7 +165,7 @@
android:id="@+id/setup_crash_reporting"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="4dp"
android:layout_margin="5dp"
android:checked="false"
android:key="pref_crash_reporting_enabled"
android:text="@string/setup_crash_reporting"
@ -184,7 +186,7 @@
android:id="@+id/setup_crash_reporting_pii"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="4dp"
android:layout_margin="5dp"
android:checked="false"
android:key="pref_crash_reporting_pii"
android:text="@string/setup_crash_reporting_pii"
@ -207,7 +209,7 @@
android:id="@+id/setup_app_analytics"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="4dp"
android:layout_margin="5dp"
android:checked="false"
android:key="pref_app_analytics"
android:text="@string/setup_app_analytics"
@ -225,7 +227,8 @@
<com.google.android.material.textview.MaterialTextView
android:layout_width="match_parent"
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:textAppearance="@android:style/TextAppearance.Material.Headline" />
@ -233,7 +236,7 @@
android:id="@+id/setup_background_update_check"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="4dp"
android:layout_margin="5dp"
android:checked="false"
android:key="pref_background_update_check"
android:text="@string/setup_background_update_check"
@ -255,7 +258,7 @@
android:id="@+id/setup_background_update_check_require_wifi"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="4dp"
android:layout_margin="5dp"
android:checked="true"
android:key="pref_background_update_check_require_wifi"
android:text="@string/setup_background_update_check_require_wifi"
@ -276,7 +279,8 @@
<com.google.android.material.textview.MaterialTextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="2dp"
android:layout_marginHorizontal="4dp"
android:layout_marginVertical="12dp"
android:text="@string/other_section"
android:textAppearance="@android:style/TextAppearance.Material.Headline" />

@ -36,16 +36,10 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
android:id="@+id/install_terminal_reboot_fab"
android:text="@string/install_terminal_reboot_now"
android:visibility="gone"
android:layout_width="wrap_content"
<com.google.android.material.bottomnavigation.BottomNavigationView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="16dp"
android:textColor="@android:color/white"
app:iconTint="@android:color/white"
app:icon="@drawable/ic_reboot_24"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintBottom_toBottomOf="parent" />
app:layout_constraintBottom_toBottomOf="parent"
app:menu="@menu/bottom_nav_install" />
</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="debug_cat">Debugging</string>
<string name="announcements">News and updates</string>
<string name="back">Go back</string>
</resources>

Loading…
Cancel
Save