fix stuff, break other stuff

aka cache is now used but that randomly makes online repo list empty :thumbs_up:

Signed-off-by: androidacy-user <opensource@androidacy.com>
pull/284/head
androidacy-user 1 year ago
parent eb838c4147
commit 40b1f4cb4c

3
.gitignore vendored

@ -9,4 +9,5 @@
.cxx
local.properties
sentry.properties
androidacy.properties
androidacy.properties
app/google-services.json

@ -24,7 +24,8 @@
android:name="android.hardware.opengles.aep"
android:required="false" />
<uses-feature
android:glEsVersion="0x00020000" android:required="false" />
android:glEsVersion="0x00020000"
android:required="false" />
<!-- Retrieve online modules -->
<uses-permission android:name="android.permission.INTERNET" />
<!-- WebView offline webpage support -->

@ -279,8 +279,10 @@ public class MainActivity extends FoxActivity implements SwipeRefreshLayout.OnRe
if (BuildConfig.DEBUG)
Timber.i("Initialize Update");
final int max = ModuleManager.getINSTANCE().getUpdatableModuleCount();
if (RepoManager.getINSTANCE().getCustomRepoManager().needUpdate()) {
if (RepoManager.getINSTANCE().getCustomRepoManager() != null && RepoManager.getINSTANCE().getCustomRepoManager().needUpdate()) {
Timber.w("Need update on create");
} else if (RepoManager.getINSTANCE().getCustomRepoManager() == null) {
Timber.w("CustomRepoManager is null");
}
// update compat metadata
if (BuildConfig.DEBUG)
@ -588,6 +590,18 @@ public class MainActivity extends FoxActivity implements SwipeRefreshLayout.OnRe
return this.overScrollInsetBottom;
}
@Override
public void onConfigurationChanged(@NonNull Configuration newConfig) {
super.onConfigurationChanged(newConfig);
this.updateScreenInsets();
}
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
this.updateScreenInsets();
}
@SuppressLint("RestrictedApi")
private void ensurePermissions() {
if (BuildConfig.DEBUG)

@ -303,8 +303,7 @@ public class SetupActivity extends FoxActivity implements LanguageActivity {
androidacy_repo.setDonate(AndroidacyRepoData.getInstance().getDonate());
androidacy_repo.setSupport(AndroidacyRepoData.getInstance().getSupport());
androidacy_repo.setSubmitModule(AndroidacyRepoData.getInstance().getSubmitModule());
androidacy_repo.setWebsite(AndroidacyRepoData.getInstance().getWebsite());
androidacy_repo.setUrl(AndroidacyRepoData.getInstance().getWebsite());
androidacy_repo.setUrl(RepoManager.ANDROIDACY_MAGISK_REPO_ENDPOINT);
androidacy_repo.setEnabled(true);
androidacy_repo.setLastUpdate(0);
androidacy_repo.setWebsite(RepoManager.ANDROIDACY_MAGISK_REPO_HOMEPAGE);
@ -319,7 +318,7 @@ public class SetupActivity extends FoxActivity implements LanguageActivity {
magisk_alt_repo.setWebsite(RepoManager.MAGISK_ALT_REPO_HOMEPAGE);
magisk_alt_repo.setSupport(null);
magisk_alt_repo.setEnabled(true);
magisk_alt_repo.setUrl(RepoManager.MAGISK_ALT_REPO_HOMEPAGE);
magisk_alt_repo.setUrl(RepoManager.MAGISK_ALT_REPO);
magisk_alt_repo.setSubmitModule(RepoManager.MAGISK_ALT_REPO_HOMEPAGE + "/submission");
magisk_alt_repo.setLastUpdate(0);
// commit the changes

@ -1,6 +1,7 @@
package com.fox2code.mmm.background;
import android.Manifest;
import android.annotation.SuppressLint;
import android.app.NotificationChannelGroup;
import android.app.NotificationManager;
import android.app.PendingIntent;
@ -24,9 +25,11 @@ import androidx.work.WorkManager;
import androidx.work.Worker;
import androidx.work.WorkerParameters;
import com.fox2code.mmm.AppUpdateManager;
import com.fox2code.mmm.MainActivity;
import com.fox2code.mmm.MainApplication;
import com.fox2code.mmm.R;
import com.fox2code.mmm.UpdateActivity;
import com.fox2code.mmm.manager.LocalModuleInfo;
import com.fox2code.mmm.manager.ModuleManager;
import com.fox2code.mmm.repo.RepoManager;
@ -42,11 +45,13 @@ import timber.log.Timber;
public class BackgroundUpdateChecker extends Worker {
public static final String NOTIFICATION_CHANNEL_ID = "background_update";
public static final String NOTIFICATION_CHANNEL_ID_APP = "background_update_app";
public static final String NOTIFICATION_CHANNEL_ID_ONGOING = "background_update_status";
public static final int NOTIFICATION_ID = 1;
public static final int NOTIFICATION_ID_ONGOING = 2;
public static final String NOTFIICATION_GROUP = "updates";
static final Object lock = new Object(); // Avoid concurrency issues
private static final int NOTIFICATION_ID_APP = 3;
public BackgroundUpdateChecker(@NonNull Context context, @NonNull WorkerParameters workerParams) {
super(context, workerParams);
@ -118,6 +123,18 @@ public class BackgroundUpdateChecker extends Worker {
postNotification(context, updateableModules, moduleUpdateCount, false);
}
});
// check for app updates
if (MainApplication.getSharedPreferences().getBoolean("pref_background_update_check_app", false)) {
try {
boolean shouldUpdate = AppUpdateManager.getAppUpdateManager().checkUpdate(true);
if (shouldUpdate) {
postNotificationForAppUpdate(context);
}
} catch (
Exception e) {
e.printStackTrace();
}
}
// remove checking notification
if (ContextCompat.checkSelfPermission(MainApplication.getINSTANCE(), Manifest.permission.POST_NOTIFICATIONS) == PackageManager.PERMISSION_GRANTED) {
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context);
@ -125,6 +142,34 @@ public class BackgroundUpdateChecker extends Worker {
}
}
@SuppressLint("RestrictedApi")
private static void postNotificationForAppUpdate(Context context) {
// create the notification channel if not already created
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context);
notificationManager.createNotificationChannel(new NotificationChannelCompat.Builder(NOTIFICATION_CHANNEL_ID_APP, NotificationManagerCompat.IMPORTANCE_HIGH).setName(context.getString(R.string.notification_channel_category_app_update)).setDescription(context.getString(R.string.notification_channel_category_app_update_description)).setGroup(NOTFIICATION_GROUP).build());
NotificationCompat.Builder builder = new NotificationCompat.Builder(context, NOTIFICATION_CHANNEL_ID_APP);
builder.setSmallIcon(R.drawable.baseline_system_update_24);
builder.setPriority(NotificationCompat.PRIORITY_HIGH);
builder.setCategory(NotificationCompat.CATEGORY_RECOMMENDATION);
builder.setShowWhen(false);
builder.setOnlyAlertOnce(true);
builder.setOngoing(false);
builder.setAutoCancel(true);
builder.setGroup(NOTFIICATION_GROUP);
// open app on click
Intent intent = new Intent(context, UpdateActivity.class);
// set action to ACTIONS.DOWNLOAD
intent.setAction(String.valueOf(UpdateActivity.ACTIONS.DOWNLOAD));
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
builder.setContentIntent(android.app.PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_IMMUTABLE));
// set summary to Found X
builder.setContentTitle(context.getString(R.string.notification_channel_background_update_app));
builder.setContentText(context.getString(R.string.notification_channel_background_update_app_description));
if (ContextCompat.checkSelfPermission(MainApplication.getINSTANCE(), Manifest.permission.POST_NOTIFICATIONS) == PackageManager.PERMISSION_GRANTED) {
notificationManager.notify(NOTIFICATION_ID_APP, builder.build());
}
}
public static void postNotification(Context context, HashMap<String, String> updateable, int updateCount, boolean test) {
NotificationCompat.Builder builder = new NotificationCompat.Builder(context, NOTIFICATION_CHANNEL_ID);
builder.setSmallIcon(R.drawable.baseline_system_update_24);
@ -166,7 +211,7 @@ public class BackgroundUpdateChecker extends Worker {
// create notification channel group
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
CharSequence groupName = context.getString(R.string.notification_group_updates);
NotificationManager mNotificationManager = (NotificationManager) ContextCompat.getSystemService(context, NotificationManager.class);
NotificationManager mNotificationManager = ContextCompat.getSystemService(context, NotificationManager.class);
Objects.requireNonNull(mNotificationManager).createNotificationChannelGroup(new NotificationChannelGroup(NOTFIICATION_GROUP, groupName));
}
NotificationManagerCompat notificationManagerCompat = NotificationManagerCompat.from(context);

@ -45,6 +45,7 @@ public class ModuleInfo {
public int maxApi;
// Module status (0 if not from Module Manager)
public int flags;
// Module safety (null if not provided)
public boolean safe;
public ModuleInfo(String id) {

@ -214,6 +214,8 @@ public final class ModuleHolder implements Comparable<ModuleHolder> {
}
if (moduleInfo.safe) {
buttonTypeList.add(ActionButtonType.SAFE);
} else {
Timber.d("Module %s is not safe", this.moduleId);
}
}

@ -107,7 +107,16 @@ public class ModuleViewListBuilder {
Timber.i("A2: %s", repoManager.getModules().size());
boolean no32bitSupport = Build.SUPPORTED_32_BIT_ABIS.length == 0;
for (RepoModule repoModule : repoManager.getModules().values()) {
if (!repoModule.repoData.isEnabled()) continue;
Timber.i("Module id %s from repo %s", repoModule.id, (repoModule.repoData == null ? "null" : repoModule.repoData.id));
// if repoData is null, something is wrong
if (repoModule.repoData == null) {
Timber.w("RepoData is null for module %s", repoModule.id);
continue;
}
if (!repoModule.repoData.isEnabled()) {
Timber.i("Repo %s is disabled, skipping module %s", repoModule.repoData.id, repoModule.id);
continue;
}
ModuleInfo moduleInfo = repoModule.moduleInfo;
if (!showIncompatible && (moduleInfo.minApi > Build.VERSION.SDK_INT ||
(moduleInfo.maxApi != 0 && moduleInfo.maxApi < Build.VERSION.SDK_INT) ||

@ -32,6 +32,7 @@ import java.util.Objects;
import io.realm.Realm;
import io.realm.RealmConfiguration;
import io.realm.RealmResults;
import timber.log.Timber;
public class RepoData extends XRepo {
@ -277,20 +278,22 @@ public class RepoData extends XRepo {
@Override
public boolean isEnabled() {
SharedPreferences preferenceManager = MainApplication.getSharedPreferences();
boolean enabled = preferenceManager.getBoolean("pref_" + this.id + "_enabled", this.isEnabledByDefault());
if (this.enabled != enabled) {
Timber.d("Repo " + this.id + " enable mismatch: " + this.enabled + " vs " + enabled);
this.enabled = enabled;
}
return this.enabled;
}
@Override
public void setEnabled(boolean enabled) {
this.enabled = enabled && !this.forceHide;
Timber.d("Repo " + this.id + " enabled: " + this.enabled + " (forced: " + this.forceHide + ") with preferenceID: " + this.getPreferenceId());
MainApplication.getSharedPreferences().edit().putBoolean("pref_" + this.getPreferenceId() + "_enabled", enabled).apply();
// reposlist realm
RealmConfiguration realmConfiguration2 = new RealmConfiguration.Builder().name("ReposList.realm").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();
if (reposList != null) {
reposList.setEnabled(enabled);
}
});
realm2.close();
}
public void updateEnabledState() {
@ -299,8 +302,10 @@ public class RepoData extends XRepo {
return;
}
this.forceHide = AppUpdateManager.shouldForceHide(this.id);
Timber.d("Repo " + this.id + " update enabled: " + this.enabled + " (forced: " + this.forceHide + ") with preferenceID: " + this.getPreferenceId());
this.enabled = (!this.forceHide) && MainApplication.getSharedPreferences().getBoolean("pref_" + this.getPreferenceId() + "_enabled", true);
// reposlist realm
RealmConfiguration realmConfiguration2 = new RealmConfiguration.Builder().name("ReposList.realm").allowQueriesOnUiThread(true).allowWritesOnUiThread(true).directory(MainApplication.getINSTANCE().getDataDirWithPath("realms")).schemaVersion(1).build();
Realm realm2 = Realm.getInstance(realmConfiguration2);
this.enabled = (!this.forceHide) && Objects.requireNonNull(realm2.where(ReposList.class).equalTo("id", this.id).findFirst()).isEnabled();
}
public String getUrl() throws NoSuchAlgorithmException {
@ -360,11 +365,12 @@ public class RepoData extends XRepo {
Realm realm2 = Realm.getInstance(realmConfiguration2);
ReposList repo = realm2.where(ReposList.class).equalTo("id", this.id).findFirst();
// Make sure ModuleListCache for repoId is not null
RealmConfiguration realmConfiguration = new RealmConfiguration.Builder().name("ModuleListCache.realm").allowQueriesOnUiThread(true).allowWritesOnUiThread(true).directory(MainApplication.getINSTANCE().getDataDirWithPath("realms/" + this.id)).schemaVersion(1).build();
File cacheRoot = MainApplication.getINSTANCE().getDataDirWithPath("realms/repos/" + this.id);
RealmConfiguration realmConfiguration = new RealmConfiguration.Builder().name("ModuleListCache.realm").schemaVersion(1).deleteRealmIfMigrationNeeded().allowWritesOnUiThread(true).allowQueriesOnUiThread(true).directory(cacheRoot).build();
Realm realm = Realm.getInstance(realmConfiguration);
ModuleListCache moduleListCache = realm.where(ModuleListCache.class).equalTo("repoId", this.id).findFirst();
RealmResults<ModuleListCache> moduleListCache = realm.where(ModuleListCache.class).equalTo("repoId", this.id).findAll();
if (repo != null) {
if (repo.getLastUpdate() != 0 && moduleListCache != null) {
if (repo.getLastUpdate() != 0 && moduleListCache.size() != 0) {
long lastUpdate = repo.getLastUpdate();
long currentTime = System.currentTimeMillis();
long diff = currentTime - lastUpdate;

@ -10,11 +10,12 @@ import org.json.JSONObject;
import java.io.File;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicBoolean;
import io.realm.Realm;
import io.realm.RealmConfiguration;
@ -47,25 +48,24 @@ public class RepoUpdater {
// if we shouldn't update, get the values from the ModuleListCache realm
if (!this.repoData.shouldUpdate()) {
Timber.d("Fetching index from cache for %s", this.repoData.id);
RealmConfiguration realmConfiguration = new RealmConfiguration.Builder()
.name("ModuleListCache.realm")
.schemaVersion(1)
.modules(new ModuleListCache())
.build();
File cacheRoot = MainApplication.getINSTANCE().getDataDirWithPath("realms/repos/" + this.repoData.id);
RealmConfiguration realmConfiguration = new RealmConfiguration.Builder().name("ModuleListCache.realm").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").allowQueriesOnUiThread(true).allowWritesOnUiThread(true).directory(MainApplication.getINSTANCE().getDataDirWithPath("realms")).schemaVersion(1).build();
Realm realm2 = Realm.getInstance(realmConfiguration2);
ReposList reposList = realm2.where(ReposList.class).equalTo("id", this.repoData.id).findFirst();
this.toUpdate = Collections.emptyList();
this.toApply = new HashSet<>();
for (ModuleListCache moduleListCache : results) {
RepoData repoData = RepoManager.getINSTANCE().get(Objects.requireNonNull(reposList).getUrl());
this.toApply.add(new RepoModule(repoData, moduleListCache.getId()));
this.toApply.add(new RepoModule(this.repoData, moduleListCache.getId()));
}
this.toApply = new HashSet<>(this.toUpdate);
Timber.d("Fetched %d modules from cache for %s", this.toApply.size(), this.repoData.id);
Timber.d("Fetched %d modules from cache for %s, from %s records", this.toApply.size(), this.repoData.id, results.size());
// close realm
realm.close();
realm2.close();
// apply the toApply list to the toUpdate list
this.toUpdate = new ArrayList<>(this.toApply);
return this.toUpdate.size();
}
try {
@ -101,7 +101,7 @@ public class RepoUpdater {
}
public boolean finish() {
boolean success = this.indexRaw != null;
var success = new AtomicBoolean(false);
// If repo is not enabled we don't need to do anything, just return true
if (!this.repoData.isEnabled()) {
return true;
@ -111,7 +111,7 @@ public class RepoUpdater {
// iterate over modules, using this.supportedProperties as a template to attempt to get each property from the module. everything that is not null is added to the module
// use realm to insert to
// 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").schemaVersion(1).deleteRealmIfMigrationNeeded().allowWritesOnUiThread(true).allowQueriesOnUiThread(true).directory(cacheRoot).build();
// array with module info default values
// supported properties for a module
@ -254,7 +254,7 @@ public class RepoUpdater {
boolean safe = false;
if (this.repoData.getName().equals("Androidacy Modules Repo")) {
if (module.has("vt_status")) {
if (module.getString("vt_status").equals("safe")) {
if (module.getString("vt_status").equals("Clean")) {
safe = true;
}
}
@ -298,7 +298,8 @@ public class RepoUpdater {
}
realm.close();
} catch (
Exception ignored) {
Exception e) {
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").allowQueriesOnUiThread(true).allowWritesOnUiThread(true).directory(MainApplication.getINSTANCE().getDataDirWithPath("realms")).schemaVersion(1).build();
@ -310,15 +311,16 @@ public class RepoUpdater {
realm2.executeTransaction(r -> {
ReposList repoListCache = r.where(ReposList.class).equalTo("id", this.repoData.id).findFirst();
if (repoListCache != null) {
success.set(true);
repoListCache.setLastUpdate((int) System.currentTimeMillis());
} else {
Timber.w("Failed to update lastUpdate for repo %s", this.repoData.id);
}
});
} else {
success.set(true); // assume we're reading from cache. this may be unsafe but it's better than nothing
}
this.toUpdate = null;
this.toApply = null;
return success;
return success.get();
}
}

@ -211,8 +211,10 @@ public class SettingsActivity extends FoxActivity implements LanguageActivity {
applyMaterial3(getPreferenceScreen());
// add bottom navigation bar to the settings
BottomNavigationView bottomNavigationView = requireActivity().findViewById(R.id.bottom_navigation);
bottomNavigationView.setVisibility(View.VISIBLE);
bottomNavigationView.getMenu().findItem(R.id.settings_menu_item).setChecked(true);
if (bottomNavigationView != null) {
bottomNavigationView.setVisibility(View.VISIBLE);
bottomNavigationView.getMenu().findItem(R.id.settings_menu_item).setChecked(true);
}
findPreference("pref_manage_repos").setOnPreferenceClickListener(p -> {
devModeStep = 0;
openFragment(new RepoFragment(), R.string.manage_repos_pref);
@ -931,7 +933,7 @@ public class SettingsActivity extends FoxActivity implements LanguageActivity {
String[][] userInfo = AndroidacyRepoData.getInstance().userInfo;
if (userInfo != null) {
String userRole = userInfo[0][1];
if (!Objects.equals(userRole, "Guest")) {
if (Objects.nonNull(userRole) && !Objects.equals(userRole, "Guest")) {
// Disable the pref_androidacy_repo_api_token preference
LongClickablePreference prefAndroidacyRepoApiD = Objects.requireNonNull(findPreference("pref_androidacy_repo_donate"));
prefAndroidacyRepoApiD.setEnabled(false);

@ -17,8 +17,7 @@ import io.sentry.android.core.SentryAndroid;
import io.sentry.android.fragment.FragmentLifecycleIntegration;
import io.sentry.android.timber.SentryTimberIntegration;
public enum SentryMain {
;
public class SentryMain {
public static final boolean IS_SENTRY_INSTALLED = true;
private static boolean sentryEnabled = false;

@ -359,5 +359,11 @@
<string name="background_update_check_excludes_no_modules">No modules installed on device</string>
<string name="auto_updates_notifs">Notifies when module updates are found</string>
<string name="notification_group_updates">Updates</string>
<string name="low_quality_module_desc">This module has metadata that is either invalid or considered a marker for a low-quality module. Uninstallation is recommended.</string><string name="online">Online</string><string name="safe">Safe</string><string name="safe_module">Verified safe module</string><string name="safe_message">This module has been verified by the repository as safe, meaning it passes certain quality and safety thresholds, and is checked for malware.</string>
<string name="low_quality_module_desc">This module has metadata that is either invalid or considered a marker for a low-quality module. Uninstallation is recommended.</string>
<string name="online">Online</string>
<string name="safe">Safe</string>
<string name="safe_module">Verified safe module</string>
<string name="safe_message">This module has been verified by the repository as safe, meaning it passes certain quality and safety thresholds, and is checked for malware.</string>
<string name="notification_update_app_desc">Enable automatically checking for app updates. Updates will not download automatically.</string>
<string name="notification_update_app_pref">Check for app updates</string><string name="notification_channel_category_app_update">App updates</string><string name="notification_channel_category_app_update_description">Notifies when an app update is available</string><string name="notification_channel_background_update_app">App update available!</string><string name="notification_channel_background_update_app_description">An update is available for FoxMMM. Tap here to update.</string>
</resources>

@ -43,11 +43,21 @@
app:summary="@string/notification_update_desc"
app:title="@string/notification_update_pref" />
<!-- check for app updates -->
<SwitchPreferenceCompat
app:defaultValue="true"
app:icon="@drawable/ic_baseline_app_settings_alt_24"
app:key="pref_background_update_check_app"
app:singleLineTitle="false"
app:summary="@string/notification_update_app_desc"
app:title="@string/notification_update_app_pref" />
<!-- require wifi -->
<SwitchPreferenceCompat
app:defaultValue="true"
app:icon="@drawable/baseline_network_wifi_24"
app:key="pref_background_update_check_wifi"
app:dependency="pref_background_update_check"
app:singleLineTitle="false"
app:summary="@string/notification_update_wifi_pref"
app:title="@string/notification_update_wifi_desc" />

@ -27,7 +27,8 @@ buildscript {
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
classpath "io.realm:realm-gradle-plugin:10.13.1-transformer-api"
//noinspection GradleDependency
classpath "io.realm:realm-gradle-plugin:10.13.3-transformer-api-SNAPSHOT"
}
}

Loading…
Cancel
Save