Update SettingsFragment to Kotlin

This commit is contained in:
topjohnwu 2019-06-09 03:04:37 -07:00
parent 1c8846dc57
commit 3e58d502d0
3 changed files with 274 additions and 325 deletions

View File

@ -15,17 +15,13 @@ import com.topjohnwu.magisk.App
import com.topjohnwu.magisk.Config import com.topjohnwu.magisk.Config
import com.topjohnwu.magisk.KConfig import com.topjohnwu.magisk.KConfig
import com.topjohnwu.magisk.R import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.data.database.RepoDatabaseHelper
import com.topjohnwu.magisk.data.repository.SettingRepository
import org.koin.android.ext.android.inject import org.koin.android.ext.android.inject
abstract class BasePreferenceFragment : PreferenceFragmentCompat(), abstract class BasePreferenceFragment : PreferenceFragmentCompat(),
SharedPreferences.OnSharedPreferenceChangeListener { SharedPreferences.OnSharedPreferenceChangeListener {
protected val repoDatabase: RepoDatabaseHelper by inject()
protected val prefs: SharedPreferences by inject() protected val prefs: SharedPreferences by inject()
protected val app: App by inject() protected val app: App by inject()
protected val settingRepo: SettingRepository by inject()
override fun onCreateView( override fun onCreateView(
inflater: LayoutInflater, inflater: LayoutInflater,
@ -82,4 +78,8 @@ abstract class BasePreferenceFragment : PreferenceFragmentCompat(),
else -> KConfig.updateChannel else -> KConfig.updateChannel
} }
} }
protected fun <T: Preference> findPref(key: CharSequence): T {
return findPreference(key) as T
}
} }

View File

@ -1,321 +0,0 @@
package com.topjohnwu.magisk.ui.settings;
import android.annotation.SuppressLint;
import android.content.SharedPreferences;
import android.os.Build;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;
import com.topjohnwu.magisk.BuildConfig;
import com.topjohnwu.magisk.Config;
import com.topjohnwu.magisk.Const;
import com.topjohnwu.magisk.KConfig;
import com.topjohnwu.magisk.KConfig.UpdateChannel;
import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.ui.base.BasePreferenceFragment;
import com.topjohnwu.magisk.utils.DownloadApp;
import com.topjohnwu.magisk.utils.FingerprintHelper;
import com.topjohnwu.magisk.utils.LocaleManager;
import com.topjohnwu.magisk.utils.PatchAPK;
import com.topjohnwu.magisk.utils.Utils;
import com.topjohnwu.magisk.view.dialogs.FingerprintAuthDialog;
import com.topjohnwu.net.Networking;
import com.topjohnwu.superuser.Shell;
import java.io.IOException;
import java.util.Arrays;
import androidx.appcompat.app.AlertDialog;
import androidx.preference.ListPreference;
import androidx.preference.Preference;
import androidx.preference.PreferenceCategory;
import androidx.preference.PreferenceScreen;
import androidx.preference.SwitchPreferenceCompat;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
import kotlin.Pair;
public final class SettingsFragment extends BasePreferenceFragment {
private ListPreference updateChannel, autoRes, suNotification,
requestTimeout, rootConfig, multiuserConfig, nsConfig;
@SuppressWarnings("ResultOfMethodCallIgnored")
@SuppressLint("CheckResult")
private static void setLocalePreference(ListPreference lp) {
lp.setSummary("Loading");
lp.setEnabled(false);
LocaleManager.getAvailableLocales()
.flattenAsFlowable(locales -> locales)
.map(locale -> new Pair<>(locale.getDisplayName(locale), LocaleManager.toLanguageTag(locale)))
.toList()
.map(list -> {
CharSequence[] names = new CharSequence[list.size() + 1];
CharSequence[] values = new CharSequence[list.size() + 1];
names[0] = LocaleManager.getString(LocaleManager.getDefaultLocale(), R.string.system_default);
values[0] = "";
int i = 1;
for (Pair<String, String> item : list) {
names[i] = item.getFirst();
values[i++] = item.getSecond();
}
return new Pair<>(names, values);
})
.subscribeOn(Schedulers.computation())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(it -> {
lp.setEnabled(true);
lp.setEntries(it.getFirst());
lp.setEntryValues(it.getSecond());
lp.setSummary(LocaleManager.getLocale().getDisplayName(LocaleManager.getLocale()));
}, Throwable::printStackTrace);
}
@Override
public final void onStart() {
super.onStart();
setHasOptionsMenu(true);
requireActivity().setTitle(R.string.settings);
}
@Override
public final void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
getPreferenceManager().setStorageDeviceProtected();
setPreferencesFromResource(R.xml.app_settings, rootKey);
boolean showSuperuser = Utils.showSuperUser();
getPrefs().edit()
.putBoolean(Config.Key.SU_FINGERPRINT, FingerprintHelper.useFingerprint())
.apply();
PreferenceScreen prefScreen = getPreferenceScreen();
PreferenceCategory generalCatagory = (PreferenceCategory) findPreference("general");
PreferenceCategory magiskCategory = (PreferenceCategory) findPreference("magisk");
PreferenceCategory suCategory = (PreferenceCategory) findPreference("superuser");
Preference hideManager = findPreference("hide");
hideManager.setOnPreferenceClickListener(pref -> {
PatchAPK.hideManager();
return true;
});
Preference restoreManager = findPreference("restore");
restoreManager.setOnPreferenceClickListener(pref -> {
DownloadApp.restore();
return true;
});
findPreference("clear").setOnPreferenceClickListener(pref -> {
getPrefs().edit().remove(Config.Key.ETAG_KEY).apply();
getRepoDatabase().clearRepo();
//getModuleRepo().deleteAllCached().subscribeOn(Schedulers.io()).subscribe(() -> {
//}, throwable -> {
//});
Utils.toast(R.string.repo_cache_cleared, Toast.LENGTH_SHORT);
return true;
});
findPreference("hosts").setOnPreferenceClickListener(pref -> {
Shell.su("add_hosts_module").exec();
//Utils.loadModules();
Utils.toast(R.string.settings_hosts_toast, Toast.LENGTH_SHORT);
return true;
});
updateChannel = (ListPreference) findPreference(Config.Key.UPDATE_CHANNEL);
rootConfig = (ListPreference) findPreference(Config.Key.ROOT_ACCESS);
autoRes = (ListPreference) findPreference(Config.Key.SU_AUTO_RESPONSE);
requestTimeout = (ListPreference) findPreference(Config.Key.SU_REQUEST_TIMEOUT);
suNotification = (ListPreference) findPreference(Config.Key.SU_NOTIFICATION);
multiuserConfig = (ListPreference) findPreference(Config.Key.SU_MULTIUSER_MODE);
nsConfig = (ListPreference) findPreference(Config.Key.SU_MNT_NS);
SwitchPreferenceCompat reauth = (SwitchPreferenceCompat) findPreference(Config.Key.SU_REAUTH);
SwitchPreferenceCompat fingerprint = (SwitchPreferenceCompat) findPreference(Config.Key.SU_FINGERPRINT);
updateChannel.setOnPreferenceChangeListener((p, o) -> {
int channel = Integer.parseInt((String) o);
final UpdateChannel previousUpdateChannel = KConfig.getUpdateChannel();
final UpdateChannel updateChannel = getChannelCompat(channel);
KConfig.setUpdateChannel(updateChannel);
if (updateChannel == UpdateChannel.CUSTOM) {
View v = LayoutInflater.from(requireActivity()).inflate(R.layout.custom_channel_dialog, null);
EditText url = v.findViewById(R.id.custom_url);
url.setText(KConfig.getCustomUpdateChannel());
new AlertDialog.Builder(requireActivity())
.setTitle(R.string.settings_update_custom)
.setView(v)
.setPositiveButton(R.string.ok, (d, i) -> setCustomUpdateChannel(url.getText().toString()))
.setNegativeButton(R.string.close, (d, i) -> KConfig.setUpdateChannel(previousUpdateChannel))
.setOnCancelListener(d -> KConfig.setUpdateChannel(previousUpdateChannel))
.show();
}
return true;
});
setLocalePreference((ListPreference) findPreference(Config.Key.LOCALE));
/* We only show canary channels if user is already on canary channel
* or the user have already chosen canary channel */
if (!Utils.isCanary() &&
(int) Config.get(Config.Key.UPDATE_CHANNEL) < Config.Value.CANARY_CHANNEL) {
// Remove the last 2 entries
CharSequence[] entries = updateChannel.getEntries();
updateChannel.setEntries(Arrays.copyOf(entries, entries.length - 2));
}
setSummary();
// Disable dangerous settings in secondary user
if (Const.USER_ID > 0) {
suCategory.removePreference(multiuserConfig);
}
// Disable re-authentication option on Android O, it will not work
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
reauth.setEnabled(false);
reauth.setChecked(false);
reauth.setSummary(R.string.android_o_not_support);
}
// Disable fingerprint option if not possible
if (!FingerprintHelper.canUseFingerprint()) {
fingerprint.setEnabled(false);
fingerprint.setChecked(false);
fingerprint.setSummary(R.string.disable_fingerprint);
}
if (Shell.rootAccess() && Const.USER_ID == 0) {
if (getApp().getPackageName().equals(BuildConfig.APPLICATION_ID)) {
generalCatagory.removePreference(restoreManager);
} else {
if (!Networking.checkNetworkStatus(requireContext())) {
generalCatagory.removePreference(restoreManager);
}
generalCatagory.removePreference(hideManager);
}
} else {
generalCatagory.removePreference(restoreManager);
generalCatagory.removePreference(hideManager);
}
if (!showSuperuser) {
prefScreen.removePreference(suCategory);
}
if (!Shell.rootAccess()) {
prefScreen.removePreference(magiskCategory);
generalCatagory.removePreference(hideManager);
}
}
@Override
public final void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
switch (key) {
case Config.Key.ROOT_ACCESS:
case Config.Key.SU_MULTIUSER_MODE:
case Config.Key.SU_MNT_NS:
getSettingRepo().put(key, Utils.getPrefsInt(prefs, key))
.subscribe(() -> {
}, Throwable::printStackTrace);
break;
case Config.Key.DARK_THEME:
requireActivity().recreate();
break;
case Config.Key.COREONLY:
if (prefs.getBoolean(key, false)) {
try {
Const.MAGISK_DISABLE_FILE.createNewFile();
} catch (IOException ignored) {
}
} else {
Const.MAGISK_DISABLE_FILE.delete();
}
Utils.toast(R.string.settings_reboot_toast, Toast.LENGTH_LONG);
break;
case Config.Key.MAGISKHIDE:
if (prefs.getBoolean(key, false)) {
Shell.su("magiskhide --enable").submit();
} else {
Shell.su("magiskhide --disable").submit();
}
break;
case Config.Key.LOCALE:
LocaleManager.setLocale(getApp());
requireActivity().recreate();
break;
case Config.Key.UPDATE_CHANNEL:
case Config.Key.CUSTOM_CHANNEL:
//CheckUpdates.check();
break;
case Config.Key.CHECK_UPDATES:
Utils.scheduleUpdateCheck();
break;
}
setSummary(key);
}
@Override
public final boolean onPreferenceTreeClick(Preference preference) {
String key = preference.getKey();
switch (key) {
case Config.Key.SU_FINGERPRINT:
boolean checked = ((SwitchPreferenceCompat) preference).isChecked();
((SwitchPreferenceCompat) preference).setChecked(!checked);
new FingerprintAuthDialog(requireActivity(), () -> {
((SwitchPreferenceCompat) preference).setChecked(checked);
Config.set(key, checked);
}).show();
break;
}
return true;
}
private void setSummary(String key) {
switch (key) {
case Config.Key.UPDATE_CHANNEL:
int ch = Config.get(key);
ch = ch < 0 ? Config.Value.STABLE_CHANNEL : ch;
updateChannel.setSummary(getResources()
.getStringArray(R.array.update_channel)[ch]);
break;
case Config.Key.ROOT_ACCESS:
rootConfig.setSummary(getResources()
.getStringArray(R.array.su_access)[(int) Config.get(key)]);
break;
case Config.Key.SU_AUTO_RESPONSE:
autoRes.setSummary(getResources()
.getStringArray(R.array.auto_response)[(int) Config.get(key)]);
break;
case Config.Key.SU_NOTIFICATION:
suNotification.setSummary(getResources()
.getStringArray(R.array.su_notification)[(int) Config.get(key)]);
break;
case Config.Key.SU_REQUEST_TIMEOUT:
requestTimeout.setSummary(
getString(R.string.request_timeout_summary, (int) Config.get(key)));
break;
case Config.Key.SU_MULTIUSER_MODE:
multiuserConfig.setSummary(getResources()
.getStringArray(R.array.multiuser_summary)[(int) Config.get(key)]);
break;
case Config.Key.SU_MNT_NS:
nsConfig.setSummary(getResources()
.getStringArray(R.array.namespace_summary)[(int) Config.get(key)]);
break;
}
}
private void setSummary() {
setSummary(Config.Key.UPDATE_CHANNEL);
setSummary(Config.Key.ROOT_ACCESS);
setSummary(Config.Key.SU_AUTO_RESPONSE);
setSummary(Config.Key.SU_NOTIFICATION);
setSummary(Config.Key.SU_REQUEST_TIMEOUT);
setSummary(Config.Key.SU_MULTIUSER_MODE);
setSummary(Config.Key.SU_MNT_NS);
}
}

View File

@ -0,0 +1,270 @@
package com.topjohnwu.magisk.ui.settings
import android.content.SharedPreferences
import android.os.Build
import android.os.Bundle
import android.view.LayoutInflater
import android.widget.EditText
import android.widget.Toast
import androidx.appcompat.app.AlertDialog
import androidx.core.content.edit
import androidx.preference.ListPreference
import androidx.preference.Preference
import androidx.preference.PreferenceCategory
import androidx.preference.SwitchPreferenceCompat
import com.skoumal.teanity.extensions.subscribeK
import com.topjohnwu.magisk.*
import com.topjohnwu.magisk.KConfig.UpdateChannel
import com.topjohnwu.magisk.data.database.RepoDatabaseHelper
import com.topjohnwu.magisk.data.repository.SettingRepository
import com.topjohnwu.magisk.ui.base.BasePreferenceFragment
import com.topjohnwu.magisk.utils.*
import com.topjohnwu.magisk.view.dialogs.FingerprintAuthDialog
import com.topjohnwu.net.Networking
import com.topjohnwu.superuser.Shell
import org.koin.android.ext.android.inject
class SettingsFragment : BasePreferenceFragment() {
private val repoDatabase: RepoDatabaseHelper by inject()
private val settingRepo: SettingRepository by inject()
private lateinit var updateChannel: ListPreference
private lateinit var autoRes: ListPreference
private lateinit var suNotification: ListPreference
private lateinit var requestTimeout: ListPreference
private lateinit var rootConfig: ListPreference
private lateinit var multiuserConfig: ListPreference
private lateinit var nsConfig: ListPreference
override fun onStart() {
super.onStart()
setHasOptionsMenu(true)
requireActivity().setTitle(R.string.settings)
}
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
preferenceManager.setStorageDeviceProtected()
setPreferencesFromResource(R.xml.app_settings, rootKey)
updateChannel = findPref(Config.Key.UPDATE_CHANNEL)
rootConfig = findPref(Config.Key.ROOT_ACCESS)
autoRes = findPref(Config.Key.SU_AUTO_RESPONSE)
requestTimeout = findPref(Config.Key.SU_REQUEST_TIMEOUT)
suNotification = findPref(Config.Key.SU_NOTIFICATION)
multiuserConfig = findPref(Config.Key.SU_MULTIUSER_MODE)
nsConfig = findPref(Config.Key.SU_MNT_NS) as ListPreference
val reauth = findPreference(Config.Key.SU_REAUTH) as SwitchPreferenceCompat
val fingerprint = findPreference(Config.Key.SU_FINGERPRINT) as SwitchPreferenceCompat
val generalCatagory = findPreference("general") as PreferenceCategory
val magiskCategory = findPreference("magisk") as PreferenceCategory
val suCategory = findPreference("superuser") as PreferenceCategory
val hideManager = findPreference("hide")
hideManager.setOnPreferenceClickListener {
PatchAPK.hideManager()
true
}
val restoreManager = findPreference("restore")
restoreManager.setOnPreferenceClickListener {
DownloadApp.restore()
true
}
findPreference("clear").setOnPreferenceClickListener {
prefs.edit().remove(Config.Key.ETAG_KEY).apply()
repoDatabase.clearRepo()
Utils.toast(R.string.repo_cache_cleared, Toast.LENGTH_SHORT)
true
}
findPreference("hosts").setOnPreferenceClickListener {
Shell.su("add_hosts_module").exec()
Utils.toast(R.string.settings_hosts_toast, Toast.LENGTH_SHORT)
true
}
prefs.edit {
putBoolean(Config.Key.SU_FINGERPRINT, FingerprintHelper.useFingerprint())
}
updateChannel.setOnPreferenceChangeListener { _, value ->
val channel = Integer.parseInt(value as String)
val previousUpdateChannel = KConfig.updateChannel
val updateChannel = getChannelCompat(channel)
KConfig.updateChannel = updateChannel
if (updateChannel === UpdateChannel.CUSTOM) {
val v = LayoutInflater.from(requireActivity()).inflate(R.layout.custom_channel_dialog, null)
val url = v.findViewById<EditText>(R.id.custom_url)
url.setText(KConfig.customUpdateChannel)
AlertDialog.Builder(requireActivity())
.setTitle(R.string.settings_update_custom)
.setView(v)
.setPositiveButton(R.string.ok) { _, _ ->
setCustomUpdateChannel(url.text.toString()) }
.setNegativeButton(R.string.close) { _, _ ->
KConfig.updateChannel = previousUpdateChannel }
.setOnCancelListener { KConfig.updateChannel = previousUpdateChannel }
.show()
}
true
}
setLocalePreference(findPreference(Config.Key.LOCALE) as ListPreference)
/* We only show canary channels if user is already on canary channel
* or the user have already chosen canary channel */
if (!Utils.isCanary() && Config.get<Int>(Config.Key.UPDATE_CHANNEL) < Config.Value.CANARY_CHANNEL) {
// Remove the last 2 entries
val entries = updateChannel.entries
updateChannel.entries = entries.copyOf(entries.size - 2)
}
setSummary()
// Disable dangerous settings in secondary user
if (Const.USER_ID > 0) {
suCategory.removePreference(multiuserConfig)
}
// Disable re-authentication option on Android O, it will not work
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
reauth.isEnabled = false
reauth.isChecked = false
reauth.setSummary(R.string.android_o_not_support)
}
// Disable fingerprint option if not possible
if (!FingerprintHelper.canUseFingerprint()) {
fingerprint.isEnabled = false
fingerprint.isChecked = false
fingerprint.setSummary(R.string.disable_fingerprint)
}
if (Shell.rootAccess() && Const.USER_ID == 0) {
if (app.packageName == BuildConfig.APPLICATION_ID) {
generalCatagory.removePreference(restoreManager)
} else {
if (!Networking.checkNetworkStatus(requireContext())) {
generalCatagory.removePreference(restoreManager)
}
generalCatagory.removePreference(hideManager)
}
} else {
generalCatagory.removePreference(restoreManager)
generalCatagory.removePreference(hideManager)
}
if (!Utils.showSuperUser()) {
preferenceScreen.removePreference(suCategory)
}
if (!Shell.rootAccess()) {
preferenceScreen.removePreference(magiskCategory)
generalCatagory.removePreference(hideManager)
}
}
override fun onSharedPreferenceChanged(prefs: SharedPreferences, key: String) {
when (key) {
Config.Key.ROOT_ACCESS, Config.Key.SU_MULTIUSER_MODE, Config.Key.SU_MNT_NS ->
settingRepo.put(key, Utils.getPrefsInt(prefs, key)).subscribe()
Config.Key.DARK_THEME -> requireActivity().recreate()
Config.Key.COREONLY -> {
if (prefs.getBoolean(key, false)) {
runCatching {
Const.MAGISK_DISABLE_FILE.createNewFile()
}
} else {
Const.MAGISK_DISABLE_FILE.delete()
}
Utils.toast(R.string.settings_reboot_toast, Toast.LENGTH_LONG)
}
Config.Key.MAGISKHIDE -> if (prefs.getBoolean(key, false)) {
Shell.su("magiskhide --enable").submit()
} else {
Shell.su("magiskhide --disable").submit()
}
Config.Key.LOCALE -> {
LocaleManager.setLocale(app)
requireActivity().recreate()
}
Config.Key.CHECK_UPDATES -> Utils.scheduleUpdateCheck()
}
setSummary(key)
}
override fun onPreferenceTreeClick(preference: Preference): Boolean {
val key = preference.key
when (key) {
Config.Key.SU_FINGERPRINT -> {
val checked = (preference as SwitchPreferenceCompat).isChecked
preference.isChecked = !checked
FingerprintAuthDialog(requireActivity()) {
preference.isChecked = checked
Config.set(key, checked)
}.show()
}
}
return true
}
private fun setLocalePreference(lp: ListPreference) {
lp.isEnabled = false
LocaleManager.availableLocales
.map {
val names = mutableListOf<String>()
val values = mutableListOf<String>()
names.add(LocaleManager.getString(
LocaleManager.defaultLocale, R.string.system_default))
values.add("")
it.forEach { locale ->
names.add(locale.getDisplayName(locale))
values.add(LocaleManager.toLanguageTag(locale))
}
Pair(names.toTypedArray(), values.toTypedArray())
}.subscribeK { (names, values) ->
lp.isEnabled = true
lp.entries = names
lp.entryValues = values
lp.summary = LocaleManager.locale.getDisplayName(LocaleManager.locale)
}
}
private fun setSummary(key: String) {
when (key) {
Config.Key.UPDATE_CHANNEL -> {
var ch = Config.get<Int>(key)
ch = if (ch < 0) Config.Value.STABLE_CHANNEL else ch
updateChannel.summary = resources
.getStringArray(R.array.update_channel)[ch]
}
Config.Key.ROOT_ACCESS -> rootConfig.summary = resources
.getStringArray(R.array.su_access)[Config.get<Int>(key)]
Config.Key.SU_AUTO_RESPONSE -> autoRes.summary = resources
.getStringArray(R.array.auto_response)[Config.get<Int>(key)]
Config.Key.SU_NOTIFICATION -> suNotification.summary = resources
.getStringArray(R.array.su_notification)[Config.get<Int>(key)]
Config.Key.SU_REQUEST_TIMEOUT -> requestTimeout.summary =
getString(R.string.request_timeout_summary, Config.get<Int>(key))
Config.Key.SU_MULTIUSER_MODE -> multiuserConfig.summary =
resources.getStringArray(R.array.multiuser_summary)[Config.get<Int>(key)]
Config.Key.SU_MNT_NS -> nsConfig.summary = resources
.getStringArray(R.array.namespace_summary)[Config.get<Int>(key)]
}
}
private fun setSummary() {
setSummary(Config.Key.UPDATE_CHANNEL)
setSummary(Config.Key.ROOT_ACCESS)
setSummary(Config.Key.SU_AUTO_RESPONSE)
setSummary(Config.Key.SU_NOTIFICATION)
setSummary(Config.Key.SU_REQUEST_TIMEOUT)
setSummary(Config.Key.SU_MULTIUSER_MODE)
setSummary(Config.Key.SU_MNT_NS)
}
}