package com.fox2code.mmm; import static com.fox2code.mmm.utils.IntentHelper.getActivity; import android.annotation.SuppressLint; import android.content.Intent; import android.content.SharedPreferences; import android.content.res.Resources; import android.os.Build; import android.os.Bundle; import android.util.Log; import android.view.View; import android.view.WindowManager; import androidx.annotation.NonNull; import androidx.annotation.RequiresApi; import androidx.appcompat.app.ActionBar; import androidx.fragment.app.FragmentActivity; import com.fox2code.foxcompat.app.FoxActivity; import com.fox2code.mmm.androidacy.AndroidacyRepoData; import com.fox2code.mmm.databinding.ActivitySetupBinding; import com.fox2code.mmm.repo.RepoManager; import com.fox2code.mmm.utils.realm.ModuleListCache; import com.fox2code.mmm.utils.realm.ReposList; import com.fox2code.rosettax.LanguageActivity; import com.fox2code.rosettax.LanguageSwitcher; import com.google.android.material.button.MaterialButton; import com.google.android.material.dialog.MaterialAlertDialogBuilder; import com.google.android.material.materialswitch.MaterialSwitch; import com.topjohnwu.superuser.internal.UiThreadHandler; import java.util.Objects; import io.realm.Realm; import io.realm.RealmConfiguration; import io.realm.RealmResults; public class SetupActivity extends FoxActivity implements LanguageActivity { @SuppressLint({"ApplySharedPref", "RestrictedApi"}) @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); this.setTitle(R.string.setup_title); // set action bar ActionBar actionBar = getSupportActionBar(); if (actionBar != null) { // back button is close button actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_TITLE | ActionBar.DISPLAY_USE_LOGO | ActionBar.DISPLAY_SHOW_HOME); actionBar.setLogo(R.drawable.ic_foreground); // set title actionBar.setTitle(R.string.setup_title); actionBar.show(); } this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION, 0); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { createRealmDatabase(); } // Set theme SharedPreferences prefs = MainApplication.getSharedPreferences(); switch (prefs.getString("theme", "system")) { case "light": setTheme(R.style.Theme_MagiskModuleManager_Monet_Light); break; case "dark": setTheme(R.style.Theme_MagiskModuleManager_Monet_Dark); break; case "system": setTheme(R.style.Theme_MagiskModuleManager_Monet); break; case "black": setTheme(R.style.Theme_MagiskModuleManager_Monet_Black); break; case "transparent_light": setTheme(R.style.Theme_MagiskModuleManager_Transparent_Light); break; } ActivitySetupBinding binding = ActivitySetupBinding.inflate(getLayoutInflater()); setContentView(binding.getRoot()); // Show setup box. Put the setup_box in the main activity layout View view = binding.setupBox; // Make the setup_box linear layout the sole child of the root_container constraint layout setContentView(view); ((MaterialSwitch) Objects.requireNonNull(view.findViewById(R.id.setup_background_update_check))).setChecked(BuildConfig.ENABLE_AUTO_UPDATER); ((MaterialSwitch) Objects.requireNonNull(view.findViewById(R.id.setup_crash_reporting))).setChecked(BuildConfig.DEFAULT_ENABLE_CRASH_REPORTING); // Repos are a little harder, as the enabled_repos build config is an arraylist ((MaterialSwitch) Objects.requireNonNull(view.findViewById(R.id.setup_androidacy_repo))).setChecked(BuildConfig.ENABLED_REPOS.contains("androidacy_repo")); ((MaterialSwitch) Objects.requireNonNull(view.findViewById(R.id.setup_magisk_alt_repo))).setChecked(BuildConfig.ENABLED_REPOS.contains("magisk_alt_repo")); // On debug builds, log when a switch is toggled if (BuildConfig.DEBUG) { ((MaterialSwitch) Objects.requireNonNull(view.findViewById(R.id.setup_background_update_check))).setOnCheckedChangeListener((buttonView, isChecked) -> Log.i("SetupWizard", "Background Update Check: " + isChecked)); ((MaterialSwitch) Objects.requireNonNull(view.findViewById(R.id.setup_crash_reporting))).setOnCheckedChangeListener((buttonView, isChecked) -> Log.i("SetupWizard", "Crash Reporting: " + isChecked)); ((MaterialSwitch) Objects.requireNonNull(view.findViewById(R.id.setup_androidacy_repo))).setOnCheckedChangeListener((buttonView, isChecked) -> Log.i("SetupWizard", "Androidacy Repo: " + isChecked)); ((MaterialSwitch) Objects.requireNonNull(view.findViewById(R.id.setup_magisk_alt_repo))).setOnCheckedChangeListener((buttonView, isChecked) -> Log.i("SetupWizard", "Magisk Alt Repo: " + isChecked)); } // Setup popup dialogue for the setup_theme_button MaterialButton themeButton = view.findViewById(R.id.setup_theme_button); themeButton.setOnClickListener(v -> { // Create a new dialog for the theme picker MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this); builder.setTitle(R.string.setup_theme_title); // Create a new array of theme names (system, light, dark, black, transparent light) String[] themeNames = new String[]{getString(R.string.theme_system), getString(R.string.theme_light), getString(R.string.theme_dark), getString(R.string.theme_black), getString(R.string.theme_transparent_light)}; // Create a new array of theme values (system, light, dark, black, transparent_light) String[] themeValues = new String[]{"system", "light", "dark", "black", "transparent_light"}; // if pref_theme is set, check the relevant theme_* menu item, otherwise check the default (theme_system) String prefTheme = prefs.getString("pref_theme", "system"); int checkedItem = 0; switch (prefTheme) { case "system": break; case "light": checkedItem = 1; break; case "dark": checkedItem = 2; break; case "black": checkedItem = 3; break; case "transparent_light": checkedItem = 4; break; } builder.setCancelable(true); // Create the dialog builder.setSingleChoiceItems(themeNames, checkedItem, (dialog, which) -> { // Set the theme prefs.edit().putString("pref_theme", themeValues[which]).commit(); // Dismiss the dialog dialog.dismiss(); // Set the theme UiThreadHandler.handler.postDelayed(() -> { switch (prefs.getString("pref_theme", "system")) { case "light": setTheme(R.style.Theme_MagiskModuleManager_Monet_Light); break; case "dark": setTheme(R.style.Theme_MagiskModuleManager_Monet_Dark); break; case "system": setTheme(R.style.Theme_MagiskModuleManager_Monet); break; case "black": setTheme(R.style.Theme_MagiskModuleManager_Monet_Black); break; case "transparent_light": setTheme(R.style.Theme_MagiskModuleManager_Transparent_Light); break; } // restart the activity because switching to transparent pisses the rendering engine off Intent intent = getIntent(); finish(); startActivity(intent); }, 100); }); builder.show(); }); // Setup language selector MaterialButton languageSelector = view.findViewById(R.id.setup_language_button); languageSelector.setOnClickListener(preference -> { LanguageSwitcher ls = new LanguageSwitcher(Objects.requireNonNull(getActivity(this))); ls.setSupportedStringLocales(MainApplication.supportedLocales); ls.showChangeLanguageDialog((FragmentActivity) getActivity(this)); }); // Set up the buttons // Setup button MaterialButton setupButton = view.findViewById(R.id.setup_continue); setupButton.setOnClickListener(v -> { // Set first launch to false // get instance of editor SharedPreferences.Editor editor = prefs.edit(); editor.putBoolean("first_time_user", false); // Set the background update check pref editor.putBoolean("pref_background_update_check", ((MaterialSwitch) Objects.requireNonNull(view.findViewById(R.id.setup_background_update_check))).isChecked()); // Set the crash reporting pref editor.putBoolean("pref_crash_reporting", ((MaterialSwitch) Objects.requireNonNull(view.findViewById(R.id.setup_crash_reporting))).isChecked()); // Set the repos in the ReposList realm db RealmConfiguration realmConfig = new RealmConfiguration.Builder().name("ReposList.realm").schemaVersion(1).allowQueriesOnUiThread(true).allowWritesOnUiThread(true).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.getInstanceAsync(realmConfig, new Realm.Callback() { @Override public void onSuccess(@NonNull Realm realm) { realm.executeTransaction(realm1 -> { ReposList androidacyRepoDB = realm1.where(ReposList.class).equalTo("id", "androidacy_repo").findFirst(); if (androidacyRepoDB != null) { androidacyRepoDB.setEnabled(androidacyRepo); // set remaining fields from the existing db entry androidacyRepoDB.setName(androidacyRepoDB.getName()); androidacyRepoDB.setUrl(androidacyRepoDB.getUrl()); androidacyRepoDB.setLastUpdate(androidacyRepoDB.getLastUpdate()); androidacyRepoDB.setDonate(androidacyRepoDB.getDonate()); androidacyRepoDB.setSupport(androidacyRepoDB.getSupport()); } ReposList magiskAltRepoDB = realm1.where(ReposList.class).equalTo("id", "magisk_alt_repo").findFirst(); if (magiskAltRepoDB != null) { magiskAltRepoDB.setEnabled(magiskAltRepo); // set remaining fields from the existing db entry magiskAltRepoDB.setName(magiskAltRepoDB.getName()); magiskAltRepoDB.setUrl(magiskAltRepoDB.getUrl()); magiskAltRepoDB.setLastUpdate(magiskAltRepoDB.getLastUpdate()); magiskAltRepoDB.setDonate(magiskAltRepoDB.getDonate()); magiskAltRepoDB.setSupport(magiskAltRepoDB.getSupport()); } }); realm.close(); } }); // Commit the changes editor.commit(); // Sleep for 1 second to allow the user to see the changes try { Thread.sleep(500); } catch ( InterruptedException e) { e.printStackTrace(); } // Log the changes if debug if (BuildConfig.DEBUG) { Log.d("SetupWizard", "Background update check: " + prefs.getBoolean("pref_background_update_check", false)); Log.i("SetupWizard", "Crash reporting: " + prefs.getBoolean("pref_crash_reporting", false)); } // Restart the activity MainActivity.doSetupRestarting = true; Intent intent = new Intent(this, MainActivity.class); startActivity(intent); finish(); }); // Cancel button MaterialButton cancelButton = view.findViewById(R.id.setup_cancel); cancelButton.setText(R.string.cancel); cancelButton.setOnClickListener(v -> { // Set first launch to false and restart the activity prefs.edit().putBoolean("first_time_user", false).commit(); MainActivity.doSetupRestarting = true; Intent intent = new Intent(this, MainActivity.class); startActivity(intent); finish(); }); } @Override public Resources.Theme getTheme() { Resources.Theme theme = super.getTheme(); // Set the theme SharedPreferences prefs = MainApplication.getSharedPreferences(); switch (prefs.getString("pref_theme", "system")) { case "light": theme.applyStyle(R.style.Theme_MagiskModuleManager_Monet_Light, true); break; case "dark": theme.applyStyle(R.style.Theme_MagiskModuleManager_Monet_Dark, true); break; case "system": theme.applyStyle(R.style.Theme_MagiskModuleManager_Monet, true); break; case "black": theme.applyStyle(R.style.Theme_MagiskModuleManager_Monet_Black, true); break; case "transparent_light": theme.applyStyle(R.style.Theme_MagiskModuleManager_Transparent_Light, true); break; } return theme; } @Override @SuppressLint({"InlinedApi", "RestrictedApi"}) public void refreshRosettaX() { // refresh app language runOnUiThread(() -> { // refresh activity Intent intent = getIntent(); finish(); startActivity(intent); }); } // creates the realm database @RequiresApi(api = Build.VERSION_CODES.N) private void createRealmDatabase() { if (BuildConfig.DEBUG) { Log.d("Realm", "Creating Realm databases"); } // create the realm database for ModuleListCache RealmConfiguration config = new RealmConfiguration.Builder().name("ModuleListCache.realm").schemaVersion(1).build(); // do a dummy write to create the database Realm.getInstanceAsync(config, new Realm.Callback() { @Override public void onSuccess(@NonNull Realm realm) { realm.executeTransactionAsync(realm1 -> { // do nothing }); } }); // create the realm database for ReposList // next, create the realm database for ReposList RealmConfiguration config2 = new RealmConfiguration.Builder().name("ReposList.realm").schemaVersion(1).build(); // get the instance Realm.getInstanceAsync(config2, new Realm.Callback() { @Override public void onSuccess(@NonNull Realm realm1) { // drop the database if it exists realm1.executeTransactionAsync(realm2 -> realm2.delete(ReposList.class)); // create androidacy_repo and magisk_alt_repo if they don't exist under ReposList // each has id, name, donate, website, support, enabled, and lastUpdate and name // create androidacy_repo realm1.beginTransaction(); if (realm1.where(ReposList.class).equalTo("id", "androidacy_repo").findFirst() == null) { ReposList androidacy_repo = realm1.createObject(ReposList.class, "androidacy_repo"); String name = getString(R.string.androidacy_repo_name); String website = AndroidacyRepoData.getInstance().website; String donate = AndroidacyRepoData.getInstance().donate; String support = AndroidacyRepoData.getInstance().support; androidacy_repo.setName(name); androidacy_repo.setDonate(donate); androidacy_repo.setWebsite(website); androidacy_repo.setSupport(support); androidacy_repo.setEnabled(true); androidacy_repo.setLastUpdate(0); } // create magisk_alt_repo if (realm1.where(ReposList.class).equalTo("id", "magisk_alt_repo").findFirst() == null) { ReposList magisk_alt_repo = realm1.createObject(ReposList.class, "magisk_alt_repo"); magisk_alt_repo.setName("Magisk Alt Repo"); magisk_alt_repo.setDonate(null); magisk_alt_repo.setWebsite(RepoManager.MAGISK_ALT_REPO_HOMEPAGE); magisk_alt_repo.setSupport(null); magisk_alt_repo.setEnabled(true); magisk_alt_repo.setLastUpdate(0); } realm1.commitTransaction(); realm1.close(); if (BuildConfig.DEBUG) { Log.d("Realm", "Realm databases created"); // log each database Realm realm2 = Realm.getInstance(config); RealmResults moduleListCaches = realm2.where(ModuleListCache.class).findAll(); Log.d("Realm", "ModuleListCache.realm"); for (ModuleListCache moduleListCache : moduleListCaches) { Log.d("Realm", moduleListCache.toString()); } realm2.close(); Realm realm3 = Realm.getInstance(config2); RealmResults reposLists = realm3.where(ReposList.class).findAll(); Log.d("Realm", "ReposList.realm"); for (ReposList reposList : reposLists) { Log.d("Realm", reposList.toString()); } realm3.close(); } } }); } }