Skip to content

Commit

Permalink
[Settings] Improve preferences
Browse files Browse the repository at this point in the history
- Added a VirusTotalPreferences
- Moved “Use the Internet” to Privacy settings
- Added feature toggler for Log Viewer and Installer
- Display build expiry and funding campaign notices only in the main settings

Signed-off-by: Muntashir Al-Islam <[email protected]>
  • Loading branch information
MuntashirAkon committed Mar 27, 2024
1 parent 6491491 commit 385d3a1
Show file tree
Hide file tree
Showing 30 changed files with 706 additions and 145 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -44,20 +44,22 @@ public class FeatureController {
FEAT_APP_EXPLORER,
FEAT_APP_INFO,
FEAT_CODE_EDITOR,
FEAT_VIRUS_TOTAL,
})
public @interface FeatureFlags {
}

private static final int FEAT_INTERCEPTOR = 1;
private static final int FEAT_MANIFEST = 1 << 1;
private static final int FEAT_SCANNER = 1 << 2;
private static final int FEAT_INSTALLER = 1 << 3;
public static final int FEAT_INSTALLER = 1 << 3;
public static final int FEAT_USAGE_ACCESS = 1 << 4;
private static final int FEAT_LOG_VIEWER = 1 << 5;
public static final int FEAT_LOG_VIEWER = 1 << 5;
public static final int FEAT_INTERNET = 1 << 6;
private static final int FEAT_APP_EXPLORER = 1 << 7;
private static final int FEAT_APP_INFO = 1 << 8;
private static final int FEAT_CODE_EDITOR = 1 << 9;
public static final int FEAT_VIRUS_TOTAL = 1 << 10;

@NonNull
public static FeatureController getInstance() {
Expand Down Expand Up @@ -87,8 +89,8 @@ public static FeatureController getInstance() {
put(FEAT_APP_INFO, R.string.app_info);
featureFlags.add(FEAT_CODE_EDITOR);
put(FEAT_CODE_EDITOR, R.string.title_code_editor);
featureFlags.add(FEAT_INTERNET);
put(FEAT_INTERNET, R.string.toggle_internet);
featureFlags.add(FEAT_VIRUS_TOTAL);
put(FEAT_VIRUS_TOTAL, R.string.virus_total);
}
};

Expand Down Expand Up @@ -144,6 +146,10 @@ public static boolean isInternetEnabled() {
return getInstance().isEnabled(FEAT_INTERNET);
}

public static boolean isVirusTotalEnabled() {
return getInstance().isEnabled(FEAT_VIRUS_TOTAL);
}

private boolean isEnabled(@FeatureFlags int key) {
ComponentName cn;
switch (key) {
Expand All @@ -162,6 +168,8 @@ private boolean isEnabled(@FeatureFlags int key) {
case FEAT_USAGE_ACCESS:
// Only depends on flag
return (mFlags & key) != 0;
case FEAT_VIRUS_TOTAL:
return (mFlags & key) != 0 && isEnabled(FEAT_INTERNET);
case FEAT_INTERNET:
return (mFlags & key) != 0 && SelfPermissions.checkSelfPermission(Manifest.permission.INTERNET);
case FEAT_LOG_VIEWER:
Expand Down Expand Up @@ -198,6 +206,7 @@ public void modifyState(@FeatureFlags int key, boolean enabled) {
break;
case FEAT_USAGE_ACCESS:
case FEAT_INTERNET:
case FEAT_VIRUS_TOTAL:
// Only depends on flag
break;
case FEAT_LOG_VIEWER:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Bundle;
import android.text.InputType;
import android.text.TextUtils;
import android.view.inputmethod.EditorInfo;

Expand Down Expand Up @@ -52,6 +53,7 @@ public void onCreatePreferences(@Nullable Bundle savedInstanceState, @Nullable S
new TextInputDialogBuilder(requireContext(), null)
.setTitle(R.string.pref_set_home)
.setInputText(FmUtils.getDisplayablePath(Prefs.FileManager.getHome()))
.setInputInputType(InputType.TYPE_CLASS_TEXT)
.setInputImeOptions(EditorInfo.IME_ACTION_DONE | EditorInfoCompat.IME_FLAG_NO_PERSONALIZED_LEARNING)
.setNegativeButton(R.string.cancel, null)
.setPositiveButton(R.string.ok, (dialog, which, inputText, isChecked) -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,18 @@
import android.os.Build;
import android.os.Bundle;
import android.os.UserHandleHidden;
import android.text.InputType;
import android.text.SpannableStringBuilder;
import android.view.View;
import android.view.inputmethod.EditorInfo;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.util.Pair;
import androidx.core.view.inputmethod.EditorInfoCompat;
import androidx.lifecycle.ViewModelProvider;
import androidx.preference.Preference;
import androidx.preference.PreferenceCategory;
import androidx.preference.SwitchPreferenceCompat;

import com.google.android.material.dialog.MaterialAlertDialogBuilder;
Expand All @@ -39,6 +43,7 @@
import io.github.muntashirakon.dialog.ScrollableDialogBuilder;
import io.github.muntashirakon.dialog.SearchableSingleChoiceDialogBuilder;
import io.github.muntashirakon.dialog.TextInputDialogBuilder;
import io.github.muntashirakon.preference.TopSwitchPreference;

public class InstallerPreferences extends PreferenceFragment {
public static final Integer[] INSTALL_LOCATIONS = new Integer[] {
Expand All @@ -65,6 +70,19 @@ public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
mModel = new ViewModelProvider(requireActivity()).get(MainPreferencesViewModel.class);
mActivity = (SettingsActivity) requireActivity();
mPm = mActivity.getPackageManager();
boolean isInstallerEnabled = FeatureController.isInstallerEnabled();
PreferenceCategory catGeneral = requirePreference("cat_general");
PreferenceCategory catAdvanced = requirePreference("cat_advanced");
TopSwitchPreference useInstaller = requirePreference("use_installer");
useInstaller.setChecked(isInstallerEnabled);
useInstaller.setOnPreferenceChangeListener((preference, newValue) -> {
boolean isEnabled = (boolean) newValue;
enablePrefs(isEnabled, catGeneral, catAdvanced);
FeatureController.getInstance().modifyState(FeatureController.FEAT_INSTALLER, isEnabled);
return true;
});
enablePrefs(isInstallerEnabled, catGeneral, catAdvanced);

// Set installation locations
Preference installLocationPref = Objects.requireNonNull(findPreference("installer_install_location"));
installLocationPref.setSummary(INSTALL_LOCATION_NAMES[Prefs.Installer.getInstallLocation()]);
Expand Down Expand Up @@ -103,6 +121,8 @@ public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
new TextInputDialogBuilder(requireActivity(), R.string.installer_app)
.setTitle(R.string.installer_app)
.setInputText(mInstallerApp)
.setInputInputType(InputType.TYPE_CLASS_TEXT)
.setInputImeOptions(EditorInfo.IME_ACTION_DONE | EditorInfoCompat.IME_FLAG_NO_PERSONALIZED_LEARNING)
.setPositiveButton(R.string.ok, (dialog1, which1, inputText, isChecked) -> {
if (inputText == null) return;
mInstallerApp = inputText.toString().trim();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@
import androidx.core.view.inputmethod.EditorInfoCompat;
import androidx.fragment.app.FragmentActivity;
import androidx.preference.Preference;
import androidx.preference.PreferenceCategory;
import androidx.preference.SwitchPreferenceCompat;

import com.google.android.material.transition.MaterialSharedAxis;

import java.util.Arrays;
import java.util.List;
import java.util.Objects;

import io.github.muntashirakon.AppManager.R;
import io.github.muntashirakon.AppManager.logcat.helper.LogcatHelper;
Expand All @@ -30,6 +30,7 @@
import io.github.muntashirakon.dialog.SearchableMultiChoiceDialogBuilder;
import io.github.muntashirakon.dialog.SearchableSingleChoiceDialogBuilder;
import io.github.muntashirakon.dialog.TextInputDialogBuilder;
import io.github.muntashirakon.preference.TopSwitchPreference;

public class LogViewerPreferences extends PreferenceFragment {
public static final List<Integer> LOG_LEVEL_VALUES = Arrays.asList(Log.VERBOSE, Log.DEBUG, Log.INFO, Log.WARN,
Expand All @@ -50,21 +51,34 @@ public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
getPreferenceManager().setPreferenceDataStore(new SettingsDataStore());

FragmentActivity activity = requireActivity();
boolean isLogViewerEnabled = FeatureController.isLogViewerEnabled();
PreferenceCategory catAppearance = requirePreference("cat_appearance");
PreferenceCategory catConf = requirePreference("cat_conf");
PreferenceCategory catAdvanced = requirePreference("cat_advanced");
TopSwitchPreference useLogViewer = requirePreference("use_log_viewer");
useLogViewer.setChecked(isLogViewerEnabled);
useLogViewer.setOnPreferenceChangeListener((preference, newValue) -> {
boolean isEnabled = (boolean) newValue;
enablePrefs(isEnabled, catAppearance, catAdvanced, catConf);
FeatureController.getInstance().modifyState(FeatureController.FEAT_LOG_VIEWER, isEnabled);
return true;
});
enablePrefs(isLogViewerEnabled, catAppearance, catAdvanced, catConf);

SwitchPreferenceCompat expandByDefault = Objects.requireNonNull(findPreference("log_viewer_expand_by_default"));
SwitchPreferenceCompat expandByDefault = requirePreference("log_viewer_expand_by_default");
expandByDefault.setChecked(Prefs.LogViewer.expandByDefault());

SwitchPreferenceCompat showPidTidTimestamp = Objects.requireNonNull(findPreference("log_viewer_show_pid_tid_timestamp"));
SwitchPreferenceCompat showPidTidTimestamp = requirePreference("log_viewer_show_pid_tid_timestamp");
showPidTidTimestamp.setChecked(Prefs.LogViewer.showPidTidTimestamp());

SwitchPreferenceCompat omitSensitiveInfo = Objects.requireNonNull(findPreference("log_viewer_omit_sensitive_info"));
SwitchPreferenceCompat omitSensitiveInfo = requirePreference("log_viewer_omit_sensitive_info");
omitSensitiveInfo.setChecked(Prefs.LogViewer.omitSensitiveInfo());
omitSensitiveInfo.setOnPreferenceChangeListener((preference, newValue) -> {
LogLine.omitSensitiveInfo = (boolean) newValue;
return true;
});

Preference filterPattern = Objects.requireNonNull(findPreference("log_viewer_filter_pattern"));
Preference filterPattern = requirePreference("log_viewer_filter_pattern");
filterPattern.setOnPreferenceClickListener(preference -> {
new TextInputDialogBuilder(activity, null)
.setTitle(R.string.pref_filter_pattern_title)
Expand All @@ -85,7 +99,7 @@ public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
return true;
});

Preference displayLimit = Objects.requireNonNull(findPreference("log_viewer_display_limit"));
Preference displayLimit = requirePreference("log_viewer_display_limit");
displayLimit.setSummary(getString(R.string.pref_display_limit_summary, Prefs.LogViewer.getDisplayLimit()));
displayLimit.setOnPreferenceClickListener(preference -> {
new TextInputDialogBuilder(activity, null)
Expand Down Expand Up @@ -117,7 +131,7 @@ public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
return true;
});

Preference writePeriod = Objects.requireNonNull(findPreference("log_viewer_write_period"));
Preference writePeriod = requirePreference("log_viewer_write_period");
writePeriod.setSummary(getString(R.string.pref_log_write_period_summary, Prefs.LogViewer.getLogWritingInterval()));
writePeriod.setOnPreferenceClickListener(preference -> {
new TextInputDialogBuilder(activity, null)
Expand Down Expand Up @@ -149,7 +163,7 @@ public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
return true;
});

Preference logLevel = Objects.requireNonNull(findPreference("log_viewer_default_log_level"));
Preference logLevel = requirePreference("log_viewer_default_log_level");
logLevel.setOnPreferenceClickListener(preference -> {
CharSequence[] logLevelsLocalised = getResources().getStringArray(R.array.log_levels);
new SearchableSingleChoiceDialogBuilder<>(activity, LOG_LEVEL_VALUES, logLevelsLocalised)
Expand All @@ -166,13 +180,13 @@ public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
return true;
});

Preference logBuffers = Objects.requireNonNull(findPreference("log_viewer_buffer"));
Preference logBuffers = requirePreference("log_viewer_buffer");
logBuffers.setOnPreferenceClickListener(preference -> {
new SearchableMultiChoiceDialogBuilder<>(activity, LOG_BUFFERS, LOG_BUFFER_NAMES)
.setTitle(R.string.pref_buffer_title)
.addSelections(PreferenceHelper.getBuffers())
.setPositiveButton(R.string.save, (dialog, which, selectedItems) -> {
if (selectedItems.size() == 0) return;
if (selectedItems.isEmpty()) return;
int bufferFlags = 0;
for (int flag : selectedItems) {
bufferFlags |= flag;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,23 +16,23 @@
import androidx.lifecycle.ViewModelProvider;
import androidx.preference.Preference;

import com.google.android.material.transition.MaterialSharedAxis;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Objects;

import io.github.muntashirakon.AppManager.R;
import io.github.muntashirakon.AppManager.misc.DeviceInfo2;
import io.github.muntashirakon.AppManager.self.life.BuildExpiryChecker;
import io.github.muntashirakon.AppManager.self.life.FundingCampaignChecker;
import io.github.muntashirakon.AppManager.servermanager.ServerConfig;
import io.github.muntashirakon.AppManager.utils.LangUtils;
import io.github.muntashirakon.AppManager.utils.UIUtils;
import io.github.muntashirakon.AppManager.utils.appearance.AppearanceUtils;
import io.github.muntashirakon.dialog.AlertDialogBuilder;
import io.github.muntashirakon.dialog.SearchableSingleChoiceDialogBuilder;
import io.github.muntashirakon.dialog.TextInputDialogBuilder;
import io.github.muntashirakon.preference.InfoAlertPreference;
import io.github.muntashirakon.preference.WarningAlertPreference;

public class MainPreferences extends PreferenceFragment {
@NonNull
Expand Down Expand Up @@ -66,6 +66,12 @@ public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
getPreferenceManager().setPreferenceDataStore(new SettingsDataStore());
mModel = new ViewModelProvider(requireActivity()).get(MainPreferencesViewModel.class);
mActivity = requireActivity();
// Expiry notice
WarningAlertPreference buildExpiringNotice = requirePreference("app_manager_expiring_notice");
buildExpiringNotice.setVisible(!Boolean.FALSE.equals(BuildExpiryChecker.buildExpired()));
// Funding campaign notice
InfoAlertPreference fundingCampaignNotice = requirePreference("funding_campaign_notice");
fundingCampaignNotice.setVisible(FundingCampaignChecker.campaignRunning());
// Custom locale
mCurrentLang = Prefs.Appearance.getLanguage();
ArrayMap<String, Locale> locales = LangUtils.getAppLanguages(mActivity);
Expand All @@ -78,7 +84,7 @@ public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
if (localeIndex < 0) {
localeIndex = locales.indexOfKey(LangUtils.LANG_AUTO);
}
Preference locale = Objects.requireNonNull(findPreference("custom_locale"));
Preference locale = requirePreference("custom_locale");
locale.setSummary(languageNames[localeIndex]);
int finalLocaleIndex = localeIndex;
locale.setOnPreferenceClickListener(preference -> {
Expand All @@ -97,7 +103,7 @@ public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
return true;
});
// Mode of operation
mModePref = Objects.requireNonNull(findPreference("mode_of_operations"));
mModePref = requirePreference("mode_of_operations");
mModeOfOpsAlertDialog = UIUtils.getProgressDialog(mActivity, getString(R.string.loading), true);
mModes = getResources().getStringArray(R.array.modes);
mCurrentMode = Ops.getMode();
Expand Down Expand Up @@ -125,38 +131,12 @@ public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
.show();
return true;
});
// VT API key
((Preference) Objects.requireNonNull(findPreference("vt_apikey"))).setOnPreferenceClickListener(preference -> {
new TextInputDialogBuilder(mActivity, null)
.setTitle(R.string.pref_vt_apikey)
.setHelperText(getString(R.string.pref_vt_apikey_description) + "\n\n" + getString(R.string.vt_disclaimer))
.setInputText(Prefs.VirusTotal.getApiKey())
.setCheckboxLabel(R.string.pref_vt_prompt_before_uploading)
.setChecked(Prefs.VirusTotal.promptBeforeUpload())
.setNegativeButton(R.string.cancel, null)
.setPositiveButton(R.string.save, (dialog, which, inputText, isChecked) -> {
if (inputText != null) {
Prefs.VirusTotal.setApiKey(inputText.toString());
}
Prefs.VirusTotal.setPromptBeforeUpload(isChecked);
})
.show();
// About device
requirePreference("about_device").setOnPreferenceClickListener(preference -> {
mModel.loadDeviceInfo(new DeviceInfo2(mActivity));
return true;
});
// About device
((Preference) Objects.requireNonNull(findPreference("about_device")))
.setOnPreferenceClickListener(preference -> {
mModel.loadDeviceInfo(new DeviceInfo2(mActivity));
return true;
});

// Hide preferences for disabled features
if (!FeatureController.isInstallerEnabled()) {
((Preference) Objects.requireNonNull(findPreference("installer"))).setVisible(false);
}
if (!FeatureController.isLogViewerEnabled()) {
((Preference) Objects.requireNonNull(findPreference("log_viewer_prefs"))).setVisible(false);
}
mModel.getOperationCompletedLiveData().observe(requireActivity(), completed -> {
if (requireActivity() instanceof SettingsActivity) {
((SettingsActivity) requireActivity()).progressIndicator.hide();
Expand All @@ -165,13 +145,6 @@ public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
});
}

@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setExitTransition(new MaterialSharedAxis(MaterialSharedAxis.Z, true));
setReenterTransition(new MaterialSharedAxis(MaterialSharedAxis.Z, false));
}

@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
import androidx.preference.PreferenceFragmentCompat;
import androidx.recyclerview.widget.RecyclerView;

import java.util.Objects;

import io.github.muntashirakon.AppManager.R;
import io.github.muntashirakon.util.UiUtils;

Expand Down Expand Up @@ -54,6 +56,19 @@ public void setPrefKey(@Nullable String prefKey) {
updateUi();
}

public <T extends androidx.preference.Preference> T requirePreference(CharSequence key) {
return Objects.requireNonNull(findPreference(key));
}

protected void enablePrefs(boolean enable, Preference ...prefs) {
if (prefs == null) {
return;
}
for (Preference pref : prefs) {
pref.setEnabled(enable);
}
}

@SuppressLint("RestrictedApi")
private void updateUi() {
if (mPrefKey != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -647,9 +647,5 @@ public static void setApiKey(@Nullable String apiKey) {
public static boolean promptBeforeUpload() {
return AppPref.getBoolean(AppPref.PrefKey.PREF_VIRUS_TOTAL_PROMPT_BEFORE_UPLOADING_BOOL);
}

public static void setPromptBeforeUpload(boolean prompt) {
AppPref.set(AppPref.PrefKey.PREF_VIRUS_TOTAL_PROMPT_BEFORE_UPLOADING_BOOL, prompt);
}
}
}
Loading

0 comments on commit 385d3a1

Please sign in to comment.