From ae47689bcada3919559b2deda188fdfe7dc5f738 Mon Sep 17 00:00:00 2001 From: flawedworld <38294951+flawedworld@users.noreply.github.com> Date: Sun, 16 May 2021 00:51:15 +0100 Subject: [PATCH 001/162] Remove misleading "Google Play system update" info field --- res/xml/firmware_version.xml | 8 -------- 1 file changed, 8 deletions(-) diff --git a/res/xml/firmware_version.xml b/res/xml/firmware_version.xml index 41f7733cfb2..edc910b36cf 100644 --- a/res/xml/firmware_version.xml +++ b/res/xml/firmware_version.xml @@ -37,14 +37,6 @@ settings:enableCopying="true" settings:controller="com.android.settings.deviceinfo.firmwareversion.SecurityPatchLevelPreferenceController"/> - - - Date: Sun, 28 May 2023 18:42:41 +0300 Subject: [PATCH 002/162] extend list of system apps that are not allowed to be disabled --- .../ApplicationFeatureProviderImpl.java | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/src/com/android/settings/applications/ApplicationFeatureProviderImpl.java b/src/com/android/settings/applications/ApplicationFeatureProviderImpl.java index 62c5910904a..c078f951269 100644 --- a/src/com/android/settings/applications/ApplicationFeatureProviderImpl.java +++ b/src/com/android/settings/applications/ApplicationFeatureProviderImpl.java @@ -22,12 +22,14 @@ import android.content.Context; import android.content.Intent; import android.content.pm.ActivityInfo; +import android.content.pm.ApplicationInfo; import android.content.pm.ComponentInfo; import android.content.pm.IPackageManager; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; import android.content.pm.UserInfo; +import android.ext.PackageId; import android.location.LocationManager; import android.os.RemoteException; import android.os.SystemConfigManager; @@ -201,6 +203,42 @@ private Set getEnabledPackageAllowlist() { if (mPm.getWellbeingPackageName() != null) { keepEnabledPackages.add(mPm.getWellbeingPackageName()); } + + ArraySet systemPkgs = new ArraySet<>(new String[] { + // Bundled keyboard, needed for text input in Direct Boot mode if the selected 3rd + // party keyboard doesn't support it + "com.android.inputmethod.latin", + + // Replacing WebView is not supported + "app.vanadium.webview", + + // Only bundled camera can handle some of camera intents + "app.grapheneos.camera", + + // Disabling GmsCompat app breaks the GmsCompat layer + com.android.internal.gmscompat.GmsCompatApp.PKG_NAME, + + // EuiccSupportPixel handles firmware updates of embedded secure element that is + // used for eSIM, NFC, Felica etc + PackageId.EUICC_SUPPORT_PIXEL_NAME, + + // CameraX extensions break when it's disabled, which breaks apps that use the + // CameraX library + PackageId.PIXEL_CAMERA_SERVICES_NAME, + + // Emergency calls break when it's disabled, system dialer app is required for it. + "com.android.dialer", + }); + + PackageManager pm = mContext.getPackageManager(); + + for (ApplicationInfo ai : pm.getInstalledApplications(PackageManager.MATCH_SYSTEM_ONLY)) { + String pkgName = ai.packageName; + if (systemPkgs.contains(pkgName)) { + keepEnabledPackages.add(pkgName); + } + } + return keepEnabledPackages; } From 39129314f189d50ef64c3033ebe1bf2a02b2e025 Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Sun, 12 Feb 2023 20:21:09 +0200 Subject: [PATCH 003/162] add a separate file for non-AOSP strings --- res/values/strings_ext.xml | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 res/values/strings_ext.xml diff --git a/res/values/strings_ext.xml b/res/values/strings_ext.xml new file mode 100644 index 00000000000..6da1fca2c7a --- /dev/null +++ b/res/values/strings_ext.xml @@ -0,0 +1,6 @@ + + + + + + From e4e83960e90073a81a9219364e175bdf4e0538ff Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Thu, 6 Apr 2023 12:06:11 +0300 Subject: [PATCH 004/162] add a set of base classes for creating Fragment-based preference UI --- res/values/strings_ext.xml | 4 +- .../settings/ext/BoolSettingFragment.java | 157 ++++++++++++++++++ .../BoolSettingFragmentPrefController.java | 26 +++ .../ext/ExtSettingFragmentPrefController.java | 42 +++++ .../settings/ext/FragmentPrefController.java | 36 ++++ 5 files changed, 264 insertions(+), 1 deletion(-) create mode 100644 src/com/android/settings/ext/BoolSettingFragment.java create mode 100644 src/com/android/settings/ext/BoolSettingFragmentPrefController.java create mode 100644 src/com/android/settings/ext/ExtSettingFragmentPrefController.java create mode 100644 src/com/android/settings/ext/FragmentPrefController.java diff --git a/res/values/strings_ext.xml b/res/values/strings_ext.xml index 6da1fca2c7a..f249f7fa627 100644 --- a/res/values/strings_ext.xml +++ b/res/values/strings_ext.xml @@ -1,6 +1,8 @@ - + Enable + Enabled + Disabled diff --git a/src/com/android/settings/ext/BoolSettingFragment.java b/src/com/android/settings/ext/BoolSettingFragment.java new file mode 100644 index 00000000000..e342faa688d --- /dev/null +++ b/src/com/android/settings/ext/BoolSettingFragment.java @@ -0,0 +1,157 @@ +package com.android.settings.ext; + +import android.content.Context; +import android.content.Intent; +import android.ext.settings.BoolSetting; +import android.net.Uri; +import android.os.Bundle; + +import androidx.preference.PreferenceScreen; +import androidx.preference.SwitchPreferenceCompat; + +import com.android.settings.R; +import com.android.settings.dashboard.DashboardFragment; +import com.android.settingslib.widget.FooterPreference; + +public abstract class BoolSettingFragment extends DashboardFragment implements ExtSettingPrefController { + + private static final String TAG = BoolSettingFragment.class.getSimpleName(); + + protected SwitchPreferenceCompat mainSwitch; + protected boolean invertSetting; + + private ExtSettingControllerHelper helper; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + helper = new ExtSettingControllerHelper<>(requireContext(), getSetting()); + + getActivity().setTitle(getTitle()); + + Context ctx = requireContext(); + + PreferenceScreen screen = getPreferenceManager().createPreferenceScreen(ctx); + + var mainSwitch = new SwitchPreferenceCompat(ctx); + mainSwitch.setTitle(getMainSwitchTitle()); + + this.mainSwitch = mainSwitch; + refreshMainSwitch(); + + mainSwitch.setOnPreferenceChangeListener((preference, newValue) -> { + boolean state = (boolean) newValue; + + if (invertSetting) { + state = !state; + } + + if (interceptMainSwitchChange(state)) { + return false; + } + + if (!getSetting().put(requireContext(), state)) { + return false; + } + + onMainSwitchChanged(state); + + return true; + }); + + screen.addPreference(mainSwitch); + + addExtraPrefs(screen); + + FooterPreference footer = makeFooterPref(new FooterPreference.Builder(ctx)); + + if (footer != null) { + screen.addPreference(footer); + } + + setPreferenceScreen(screen); + } + + protected abstract BoolSetting getSetting(); + + protected abstract CharSequence getTitle(); + + protected CharSequence getMainSwitchTitle() { + return getText(R.string.bool_setting_enable); + } + + protected CharSequence getMainSwitchSummary() { + return null; + } + + protected void addExtraPrefs(PreferenceScreen screen) {} + + protected FooterPreference makeFooterPref(FooterPreference.Builder builder) { + return null; + } + + protected static void setFooterPrefLearnMoreUri(FooterPreference p, Uri uri) { + p.setLearnMoreAction(v -> { + var intent = new Intent(Intent.ACTION_VIEW, uri); + p.getContext().startActivity(intent); + }); + } + + protected boolean interceptMainSwitchChange(boolean newValue) { + return false; + } + + protected void onMainSwitchChanged(boolean state) {} + + protected void refreshMainSwitch() { + boolean state = getSetting().get(requireContext()); + if (invertSetting) { + state = !state; + } + mainSwitch.setChecked(state); + + CharSequence mainSwitchSummary = getMainSwitchSummary(); + if (mainSwitchSummary != null) { + mainSwitch.setSummary(mainSwitchSummary); + } + } + + @Override + public void onResume() { + super.onResume(); + helper.onResume(this); + refreshMainSwitch(); + } + + @Override + public void onPause() { + super.onPause(); + + helper.onPause(this); + } + + @Override + public void accept(BoolSetting setting) { + refreshMainSwitch(); + } + + @Override + public int getMetricsCategory() { + return METRICS_CATEGORY_UNKNOWN; + } + + @Override + protected int getPreferenceScreenResId() { + return 0; + } + + @Override + protected String getLogTag() { + return TAG; + } + + protected final CharSequence resText(int res) { + return requireContext().getText(res); + } +} diff --git a/src/com/android/settings/ext/BoolSettingFragmentPrefController.java b/src/com/android/settings/ext/BoolSettingFragmentPrefController.java new file mode 100644 index 00000000000..3f9223b800a --- /dev/null +++ b/src/com/android/settings/ext/BoolSettingFragmentPrefController.java @@ -0,0 +1,26 @@ +package com.android.settings.ext; + +import android.content.Context; +import android.ext.settings.BoolSetting; + +import com.android.settings.R; + +public abstract class BoolSettingFragmentPrefController extends ExtSettingFragmentPrefController { + + protected BoolSettingFragmentPrefController(Context ctx, String key, BoolSetting setting) { + super(ctx, key, setting); + } + + @Override + public CharSequence getSummary() { + return setting.get(mContext) ? getSummaryOn() : getSummaryOff(); + } + + protected CharSequence getSummaryOn() { + return resText(R.string.bool_setting_enabled); + } + + protected CharSequence getSummaryOff() { + return resText(R.string.bool_setting_disabled); + } +} diff --git a/src/com/android/settings/ext/ExtSettingFragmentPrefController.java b/src/com/android/settings/ext/ExtSettingFragmentPrefController.java new file mode 100644 index 00000000000..2d87635e0d2 --- /dev/null +++ b/src/com/android/settings/ext/ExtSettingFragmentPrefController.java @@ -0,0 +1,42 @@ +package com.android.settings.ext; + +import android.content.Context; +import android.ext.settings.Setting; + +import androidx.annotation.NonNull; +import androidx.lifecycle.LifecycleOwner; + +public abstract class ExtSettingFragmentPrefController extends FragmentPrefController + implements ExtSettingPrefController { + protected final T setting; + protected final ExtSettingControllerHelper helper; + + protected ExtSettingFragmentPrefController(Context ctx, String key, T setting) { + super(ctx, key); + this.setting = setting; + helper = new ExtSettingControllerHelper(ctx, setting); + } + + @Override + public int getAvailabilityStatus() { + return helper.getAvailabilityStatus(); + } + + @Override + public void onResume(@NonNull LifecycleOwner owner) { + helper.onResume(this); + } + + @Override + public void onPause(@NonNull LifecycleOwner owner) { + helper.onPause(this); + } + + // called by the setting observer + @Override + public void accept(T setting) { + if (preference != null) { + updateState(preference); + } + } +} diff --git a/src/com/android/settings/ext/FragmentPrefController.java b/src/com/android/settings/ext/FragmentPrefController.java new file mode 100644 index 00000000000..b09ab9615c2 --- /dev/null +++ b/src/com/android/settings/ext/FragmentPrefController.java @@ -0,0 +1,36 @@ +package com.android.settings.ext; + +import android.content.Context; + +import androidx.annotation.Nullable; +import androidx.preference.Preference; +import androidx.preference.PreferenceFragmentCompat; + +import com.android.settings.core.BasePreferenceController; + +public abstract class FragmentPrefController + extends BasePreferenceController { + + protected FragmentPrefController(Context ctx, String key) { + super(ctx, key); + } + + @Nullable + protected Preference preference; + + @Override + public void updateState(Preference preference) { + super.updateState(preference); + + if (preference != this.preference) { + preference.setSingleLineTitle(false); + preference.setPersistent(false); + + this.preference = preference; + } + } + + protected final CharSequence resText(int res) { + return mContext.getText(res); + } +} From bc85bb0bcd28cf681886751b44449de009588e5a Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Sun, 12 Feb 2023 19:43:44 +0200 Subject: [PATCH 005/162] add base class for ListPreference controllers --- .../ext/AbstractListPreferenceController.java | 242 ++++++++++++++++++ .../ext/RadioButtonPickerFragment2.java | 208 +++++++++++++++ .../widget/RadioButtonPickerFragment.java | 17 +- 3 files changed, 462 insertions(+), 5 deletions(-) create mode 100644 src/com/android/settings/ext/AbstractListPreferenceController.java create mode 100644 src/com/android/settings/ext/RadioButtonPickerFragment2.java diff --git a/src/com/android/settings/ext/AbstractListPreferenceController.java b/src/com/android/settings/ext/AbstractListPreferenceController.java new file mode 100644 index 00000000000..a5686e370ee --- /dev/null +++ b/src/com/android/settings/ext/AbstractListPreferenceController.java @@ -0,0 +1,242 @@ +/* + * Copyright (C) 2022 GrapheneOS + * SPDX-License-Identifier: Apache-2.0 + */ + +package com.android.settings.ext; + +import android.app.settings.SettingsEnums; +import android.content.Context; +import android.content.Intent; +import android.net.Uri; +import android.os.UserHandle; +import android.text.TextUtils; +import android.text.format.DateUtils; +import android.util.SparseIntArray; + +import androidx.annotation.Nullable; +import androidx.annotation.StringRes; +import androidx.lifecycle.DefaultLifecycleObserver; +import androidx.preference.ListPreference; +import androidx.preference.Preference; +import androidx.preference.PreferenceScreen; + +import com.android.settings.R; +import com.android.settings.core.BasePreferenceController; +import com.android.settings.core.SubSettingLauncher; +import com.android.settings.dashboard.DashboardFragment; +import com.android.settings.utils.CandidateInfoExtra; +import com.android.settingslib.widget.CandidateInfo; +import com.android.settingslib.widget.FooterPreference; + +import java.util.ArrayList; +import java.util.Objects; +import java.util.concurrent.TimeUnit; + +public abstract class AbstractListPreferenceController extends BasePreferenceController + implements DefaultLifecycleObserver { + + private Preference preference; + private Entries entries; + + @Nullable + public RadioButtonPickerFragment2 fragment; + + protected AbstractListPreferenceController(Context ctx, String key) { + super(ctx, key); + } + + // call entries.add(entryName, entryValue) to add entries. + // entryValues can be mapped from other values or sets of values, as long as getCurrentValue() + // and setValue() methods are consistent + protected abstract void getEntries(Entries entries); + + public void getEntriesAsCandidates(ArrayList dst) { + Entries e = new Entries(mContext); + getEntries(e); + + dst.addAll(e.list); + } + + protected abstract int getCurrentValue(); + protected abstract boolean setValue(int val); + + @Override + public void updateState(Preference p) { + if (entries == null) { + entries = new Entries(mContext); + getEntries(entries); + } + + if (p != preference) { + p.setSingleLineTitle(false); + p.setPersistent(false); + this.preference = p; + } + + updatePreference(); + } + + void updatePreference() { + if (fragment != null) { + fragment.updateCandidates(); + } + + Preference p = preference; + if (p == null) { + return; + } + + int idx = entries.getIndexForValue(getCurrentValue()); + if (idx >= 0) { + p.setSummary(entries.list.get(idx).loadLabel()); + } else { + p.setSummary(null); + } + } + + public static class Entries { + private final Context context; + private final ArrayList list = new ArrayList<>(); + private final SparseIntArray valueToIndexMap = new SparseIntArray(); + + Entries(Context context) { + this.context = context; + } + + public void add(@StringRes int title, int value) { + add(context.getText(title), value); + } + + public void add(@StringRes int title, @StringRes int summary, int value) { + add(context.getText(title), context.getText(summary), value); + } + + public void add(int duration, TimeUnit timeUnit) { + long durationMillis = timeUnit.toMillis(duration); + if (durationMillis > Integer.MAX_VALUE) { + throw new IllegalArgumentException(); + } + + add(DateUtils.formatDuration(durationMillis), (int) durationMillis); + } + + public void add(CharSequence title, int value) { + add(title, null, value, true); + } + + public void add(CharSequence title, CharSequence summary, int value) { + add(title, summary, value, true); + } + + public void add(CharSequence title, @Nullable CharSequence summary, int value, boolean enabled) { + String prefKey = Integer.toString(value); + list.add(new CandidateInfoExtra(title, summary, prefKey, enabled)); + valueToIndexMap.put(value, list.size() - 1); + } + + public int getIndexForValue(int val) { + return valueToIndexMap.get(val, -1); + } + } + + @Override + public boolean isSliceable() { + return false; + } + + @Override + public int getSliceHighlightMenuRes() { + return NO_RES; + } + + @Override + public boolean handlePreferenceTreeClick(Preference preference) { + if (!TextUtils.equals(preference.getKey(), getPreferenceKey())) { + return super.handlePreferenceTreeClick(preference); + } + + if (this.preference instanceof ListPreference) { + return super.handlePreferenceTreeClick(preference); + } + + UserHandle workProfileUser = getWorkProfileUser(); + boolean isForWork = workProfileUser != null; + + RadioButtonPickerFragment2.fillArgs(preference, this, isForWork); + + new SubSettingLauncher(preference.getContext()) + .setDestination(RadioButtonPickerFragment2.class.getName()) + .setSourceMetricsCategory(preference.getExtras().getInt(DashboardFragment.CATEGORY, + SettingsEnums.PAGE_UNKNOWN)) + .setTitleText(preference.getTitle()) + .setArguments(preference.getExtras()) + .setUserHandle(workProfileUser) + .launch(); + return true; + } + + public void addPrefsBeforeList(RadioButtonPickerFragment2 fragment, PreferenceScreen screen) { + + } + + public void addPrefsAfterList(RadioButtonPickerFragment2 fragment, PreferenceScreen screen) { + + } + + public FooterPreference addFooterPreference(PreferenceScreen screen, @StringRes int text) { + Context ctx = screen.getContext(); + return addFooterPreference(screen, ctx.getText(text), null, null); + } + + public FooterPreference addFooterPreference(PreferenceScreen screen, + @StringRes int text, String learnMoreUrl) { + return addFooterPreference(screen, text, R.string.learn_more, learnMoreUrl); + } + + public FooterPreference addFooterPreference( + PreferenceScreen screen, @StringRes int text, + @StringRes int learnMoreText, String learnMoreUrl) { + Context ctx = screen.getContext(); + Runnable learnMoreAction = () -> { + var intent = new Intent(Intent.ACTION_VIEW, Uri.parse(learnMoreUrl)); + ctx.startActivity(intent); + }; + return addFooterPreference(screen, ctx.getText(text), + ctx.getText(learnMoreText), learnMoreAction); + } + + public FooterPreference addFooterPreference( + PreferenceScreen screen, @StringRes int text, + @StringRes int learnMoreText, Runnable learnMoreAction) { + Context ctx = screen.getContext(); + return addFooterPreference(screen, ctx.getText(text), ctx.getText(learnMoreText), learnMoreAction); + } + + public FooterPreference addFooterPreference(PreferenceScreen screen, CharSequence text, + @Nullable CharSequence learnMoreText, + @Nullable Runnable learnMoreAction) { + var p = new FooterPreference(screen.getContext()); + p.setSelectable(false); + p.setSummary(text); + if (learnMoreText != null) { + p.setLearnMoreText(learnMoreText); + Objects.requireNonNull(learnMoreAction); + p.setLearnMoreAction(v -> learnMoreAction.run()); + } + p.setOrder(Preference.DEFAULT_ORDER); + screen.addPreference(p); + return p; + } + + protected final CharSequence getText(@StringRes int resId) { + return mContext.getText(resId); + } + + /** + * Returns whether to require user credential confirmation before changing this preference. + */ + protected boolean isCredentialConfirmationRequired() { + return false; + } +} diff --git a/src/com/android/settings/ext/RadioButtonPickerFragment2.java b/src/com/android/settings/ext/RadioButtonPickerFragment2.java new file mode 100644 index 00000000000..a44c9280af7 --- /dev/null +++ b/src/com/android/settings/ext/RadioButtonPickerFragment2.java @@ -0,0 +1,208 @@ +package com.android.settings.ext; + +import android.app.Activity; +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; + +import androidx.activity.result.ActivityResult; +import androidx.activity.result.ActivityResultLauncher; +import androidx.activity.result.contract.ActivityResultContracts; +import androidx.annotation.Nullable; +import androidx.preference.Preference; +import androidx.preference.PreferenceScreen; + +import com.android.internal.widget.LockPatternUtils; +import com.android.settings.core.BasePreferenceController; +import com.android.settings.overlay.FeatureFactory; +import com.android.settings.password.ChooseLockSettingsHelper; +import com.android.settings.utils.CandidateInfoExtra; +import com.android.settings.widget.RadioButtonPickerFragment; +import com.android.settingslib.widget.CandidateInfo; +import com.android.settingslib.widget.SelectorWithWidgetPreference; + +import java.util.ArrayList; +import java.util.List; + +public class RadioButtonPickerFragment2 extends RadioButtonPickerFragment { + + private final ArrayList candidates = new ArrayList<>(); + + static final String KEY_PREF_CONTROLLER_CLASS = "pref_controller"; + static final String KEY_PREF_KEY = "pref_key"; + + private AbstractListPreferenceController prefController; + + public static void fillArgs(Preference pref, AbstractListPreferenceController pc, boolean isForWork) { + Bundle args = pref.getExtras(); + args.putString(KEY_PREF_CONTROLLER_CLASS, pc.getClass().getName()); + args.putString(KEY_PREF_KEY, pc.getPreferenceKey()); + args.putBoolean(EXTRA_FOR_WORK, isForWork); + } + + @Override + public void onCreate(Bundle savedInstanceState) { + Bundle args = requireArguments(); + String prefControllerClass = args.getString(KEY_PREF_CONTROLLER_CLASS); + String prefKey = args.getString(KEY_PREF_KEY); + boolean forWork = args.getBoolean(EXTRA_FOR_WORK); + + Context ctx = requireContext(); + + prefController = (AbstractListPreferenceController) BasePreferenceController + .createInstance(ctx,prefControllerClass, prefKey, forWork); + prefController.fragment = this; + + super.onCreate(savedInstanceState); + } + + private static final String KEY_USER_CREDENTIAL_CONFIRMED = "user_credential_confirmed"; + private boolean userCredentialConfirmed; + + @Override + public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { + PreferenceScreen ps = getPreferenceManager().createPreferenceScreen(requireContext()); + setPreferenceScreen(ps); + + if (savedInstanceState != null) { + userCredentialConfirmed = savedInstanceState.getBoolean( + KEY_USER_CREDENTIAL_CONFIRMED, false); + } + + updateCandidates(); + } + + @Override + public void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + outState.putBoolean(KEY_USER_CREDENTIAL_CONFIRMED, userCredentialConfirmed); + } + + private Runnable onAfterCredentialConfirmed; + + private void runAfterCredentialConfirmation(Runnable runnable) { + if (userCredentialConfirmed) { + throw new IllegalStateException(); + } + + if (onAfterCredentialConfirmed != null) { + throw new IllegalStateException(); + } + + onAfterCredentialConfirmed = runnable; + + var b = new ChooseLockSettingsHelper.Builder(requireActivity()); + b.setActivityResultLauncher(credentialConfirmationLauncher); + b.setForegroundOnly(true); + b.show(); + } + + private final ActivityResultLauncher credentialConfirmationLauncher = + registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), + this::onCredentialConfirmationResult); + + private void onCredentialConfirmationResult(@Nullable ActivityResult result) { + Runnable r = onAfterCredentialConfirmed; + onAfterCredentialConfirmed = null; + + if (result != null && result.getResultCode() == Activity.RESULT_OK) { + userCredentialConfirmed = true; + if (r != null) { + r.run(); + } + } + } + + @Override + public void onStop() { + super.onStop(); + if (!requireActivity().isChangingConfigurations()) { + userCredentialConfirmed = false; + } + } + + @Override + protected int getPreferenceScreenResId() { + return -1; + } + + @Override + protected List getCandidates() { + candidates.clear(); + prefController.getEntriesAsCandidates(candidates); + return candidates; + } + + @Override + protected void addPrefsBeforeList(PreferenceScreen screen) { + prefController.addPrefsBeforeList(this, screen); + } + + @Override + protected void addPrefsAfterList(PreferenceScreen screen) { + prefController.addPrefsAfterList(this, screen); + } + + @Override + protected String getDefaultKey() { + return Integer.toString(prefController.getCurrentValue()); + } + + @Override + protected boolean setDefaultKey(String key) { + if (key.equals(getDefaultKey())) { + return true; + } + + if (!userCredentialConfirmed && prefController.isCredentialConfirmationRequired()) { + Context ctx = requireContext(); + LockPatternUtils lpu = FeatureFactory.getFeatureFactory() + .getSecurityFeatureProvider() + .getLockPatternUtils(ctx); + + if (lpu.isSecure(ctx.getUserId())) { + runAfterCredentialConfirmation(() -> prefController.setValue(Integer.parseInt(key))); + return false; + } + } + + return prefController.setValue(Integer.parseInt(key)); + } + + @Override + public void bindPreferenceExtra(SelectorWithWidgetPreference pref, String key, CandidateInfo info, + String defaultKey, String systemDefaultKey) { + pref.setSingleLineTitle(false); + + if (info instanceof CandidateInfoExtra) { + var cie = (CandidateInfoExtra) info; + pref.setSummary(cie.loadSummary()); + } + } + + @Override + public int getMetricsCategory() { + return METRICS_CATEGORY_UNKNOWN; + } + + @Override + public void onPause() { + super.onPause(); + prefController.onPause(this); + } + + private boolean updateCandidatesOnResume; + + @Override + public void onResume() { + super.onResume(); + prefController.onResume(this); + + if (updateCandidatesOnResume) { + updateCandidates(); + } else { + // updateCandidates() is called from onCreatePrefences() right before the first onResume() + updateCandidatesOnResume = true; + } + } +} diff --git a/src/com/android/settings/widget/RadioButtonPickerFragment.java b/src/com/android/settings/widget/RadioButtonPickerFragment.java index 9578efbb55d..4927e221609 100644 --- a/src/com/android/settings/widget/RadioButtonPickerFragment.java +++ b/src/com/android/settings/widget/RadioButtonPickerFragment.java @@ -62,8 +62,7 @@ public abstract class RadioButtonPickerFragment extends SettingsPreferenceFragme SelectorWithWidgetPreference.OnClickListener { @VisibleForTesting - static final String EXTRA_FOR_WORK = "for_work"; - + protected static final String EXTRA_FOR_WORK = "for_work"; private static final String TAG = "RadioButtonPckrFrgmt"; private static final String KEY_CATEGORY_PREFERENCE = "radio_button_picker_category"; @VisibleForTesting @@ -182,6 +181,12 @@ protected SelectorWithWidgetPreference createPreference() { return new RestrictedSelectorWithWidgetPreference(getPrefContext()); } + protected void addPrefsBeforeList(PreferenceScreen screen) { + if (!mAppendStaticPreferences) { + addStaticPreferences(screen); + } + } + public void updateCandidates() { mCandidates.clear(); final List candidateList = getCandidates(); @@ -197,9 +202,7 @@ public void updateCandidates() { if (mIllustrationId != 0) { addIllustration(screen); } - if (!mAppendStaticPreferences) { - addStaticPreferences(screen); - } + addPrefsBeforeList(screen); PreferenceGroup radioButtonsGroup = screen; if (mCategoryTitleId != 0) { Context context = getPrefContext(); @@ -235,6 +238,10 @@ public void updateCandidates() { } } mayCheckOnlyRadioButton(); + addPrefsAfterList(screen); + } + + protected void addPrefsAfterList(PreferenceScreen screen) { if (mAppendStaticPreferences) { addStaticPreferences(screen); } From 0924b565ae30222863ed037f6dfb2c97914c9a4b Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Tue, 14 Feb 2023 08:45:56 +0200 Subject: [PATCH 006/162] add base class for toggle preference controllers --- .../ext/AbstractTogglePrefController.java | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 src/com/android/settings/ext/AbstractTogglePrefController.java diff --git a/src/com/android/settings/ext/AbstractTogglePrefController.java b/src/com/android/settings/ext/AbstractTogglePrefController.java new file mode 100644 index 00000000000..ceee6984bfd --- /dev/null +++ b/src/com/android/settings/ext/AbstractTogglePrefController.java @@ -0,0 +1,38 @@ +package com.android.settings.ext; + +import android.content.Context; + +import androidx.annotation.Nullable; +import androidx.preference.Preference; + +import com.android.settings.core.TogglePreferenceController; + +public abstract class AbstractTogglePrefController extends TogglePreferenceController { + + protected AbstractTogglePrefController(Context ctx, String key) { + super(ctx, key); + } + + @Nullable protected Preference preference; + + @Override + public void updateState(Preference preference) { + super.updateState(preference); + + if (preference != this.preference) { + preference.setSingleLineTitle(false); + preference.setPersistent(false); + this.preference = preference; + } + } + + @Override + public boolean isSliceable() { + return false; + } + + @Override + public int getSliceHighlightMenuRes() { + return NO_RES; + } +} From f6bcec2506a3b13c0faa442b10a0b1a5b5f8e9c3 Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Sun, 12 Feb 2023 19:44:07 +0200 Subject: [PATCH 007/162] add base classes for {Bool,Int}Setting preference controllers If no customization is needed, BoolSetting base class can be used directly from XML by adding settings:boolSettingField=" " to the preference XML definition. --- res/values/attrs.xml | 2 + .../core/PreferenceControllerListHelper.java | 3 + .../core/PreferenceXmlParserUtils.java | 12 +++ .../ext/BoolSettingPrefController.java | 96 +++++++++++++++++++ .../ext/ExtSettingControllerHelper.java | 72 ++++++++++++++ .../ext/ExtSettingPrefController.java | 12 +++ .../ext/IntSettingPrefController.java | 62 ++++++++++++ 7 files changed, 259 insertions(+) create mode 100644 src/com/android/settings/ext/BoolSettingPrefController.java create mode 100644 src/com/android/settings/ext/ExtSettingControllerHelper.java create mode 100644 src/com/android/settings/ext/ExtSettingPrefController.java create mode 100644 src/com/android/settings/ext/IntSettingPrefController.java diff --git a/res/values/attrs.xml b/res/values/attrs.xml index c5cb82de15f..589d7a3d303 100644 --- a/res/values/attrs.xml +++ b/res/values/attrs.xml @@ -66,6 +66,8 @@ + + diff --git a/src/com/android/settings/core/PreferenceControllerListHelper.java b/src/com/android/settings/core/PreferenceControllerListHelper.java index 9dc0a9fa108..30d41d88c3e 100644 --- a/src/com/android/settings/core/PreferenceControllerListHelper.java +++ b/src/com/android/settings/core/PreferenceControllerListHelper.java @@ -31,6 +31,7 @@ import androidx.preference.PreferenceScreen; import com.android.settings.core.PreferenceXmlParserUtils.MetadataFlag; +import com.android.settings.ext.BoolSettingPrefController; import com.android.settingslib.core.AbstractPreferenceController; import org.xmlpull.v1.XmlPullParserException; @@ -59,6 +60,7 @@ public static List getPreferenceControllersFromXml(Con try { preferenceMetadata = PreferenceXmlParserUtils.extractMetadata(context, xmlResId, MetadataFlag.FLAG_NEED_KEY | MetadataFlag.FLAG_NEED_PREF_CONTROLLER + | MetadataFlag.FLAG_NEED_BOOL_SETTING_FIELD | MetadataFlag.FLAG_INCLUDE_PREF_SCREEN | MetadataFlag.FLAG_FOR_WORK); } catch (IOException | XmlPullParserException e) { Log.e(TAG, "Failed to parse preference xml for getting controllers", e); @@ -68,6 +70,7 @@ public static List getPreferenceControllersFromXml(Con for (Bundle metadata : preferenceMetadata) { final String controllerName = metadata.getString(METADATA_CONTROLLER); if (TextUtils.isEmpty(controllerName)) { + BoolSettingPrefController.maybeAdd(context, metadata, controllers); continue; } BasePreferenceController controller; diff --git a/src/com/android/settings/core/PreferenceXmlParserUtils.java b/src/com/android/settings/core/PreferenceXmlParserUtils.java index cf2f9ca179b..5d4758deeff 100644 --- a/src/com/android/settings/core/PreferenceXmlParserUtils.java +++ b/src/com/android/settings/core/PreferenceXmlParserUtils.java @@ -65,6 +65,7 @@ public class PreferenceXmlParserUtils { MetadataFlag.FLAG_NEED_KEY, MetadataFlag.FLAG_NEED_PREF_TYPE, MetadataFlag.FLAG_NEED_PREF_CONTROLLER, + MetadataFlag.FLAG_NEED_BOOL_SETTING_FIELD, MetadataFlag.FLAG_NEED_PREF_TITLE, MetadataFlag.FLAG_NEED_PREF_SUMMARY, MetadataFlag.FLAG_NEED_PREF_ICON, @@ -92,11 +93,14 @@ public class PreferenceXmlParserUtils { int FLAG_FOR_WORK = 1 << 12; int FLAG_NEED_HIGHLIGHTABLE_MENU_KEY = 1 << 13; int FLAG_NEED_USER_RESTRICTION = 1 << 14; + + int FLAG_NEED_BOOL_SETTING_FIELD = 1 << 30; } public static final String METADATA_PREF_TYPE = "type"; public static final String METADATA_KEY = "key"; public static final String METADATA_CONTROLLER = "controller"; + public static final String METADATA_BOOL_SETTING_FIELD = "bool_setting_field"; public static final String METADATA_TITLE = "title"; public static final String METADATA_SUMMARY = "summary"; public static final String METADATA_ICON = "icon"; @@ -163,6 +167,10 @@ public static List extractMetadata(Context context, @XmlRes int xmlResId preferenceMetadata.putString(METADATA_CONTROLLER, getController(preferenceAttributes)); } + if (hasFlag(flags, MetadataFlag.FLAG_NEED_BOOL_SETTING_FIELD)) { + preferenceMetadata.putString(METADATA_BOOL_SETTING_FIELD, + getBoolSettingField(preferenceAttributes)); + } if (hasFlag(flags, MetadataFlag.FLAG_NEED_PREF_TITLE)) { preferenceMetadata.putString(METADATA_TITLE, getTitle(preferenceAttributes)); } @@ -231,6 +239,10 @@ private static String getController(TypedArray styledAttributes) { return styledAttributes.getString(R.styleable.Preference_controller); } + private static String getBoolSettingField(TypedArray styledAttributes) { + return styledAttributes.getString(R.styleable.Preference_boolSettingField); + } + private static String getHighlightableMenuKey(TypedArray styledAttributes) { return styledAttributes.getString(R.styleable.Preference_highlightableMenuKey); } diff --git a/src/com/android/settings/ext/BoolSettingPrefController.java b/src/com/android/settings/ext/BoolSettingPrefController.java new file mode 100644 index 00000000000..659585dc5dd --- /dev/null +++ b/src/com/android/settings/ext/BoolSettingPrefController.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2022 GrapheneOS + * SPDX-License-Identifier: Apache-2.0 + */ + +package com.android.settings.ext; + +import android.content.Context; +import android.ext.settings.BoolSetting; +import android.os.Bundle; +import android.os.UserHandle; + +import androidx.annotation.NonNull; +import androidx.lifecycle.LifecycleOwner; + +import com.android.settings.core.BasePreferenceController; + +import java.lang.reflect.Field; +import java.util.List; +import java.util.Objects; + +import static com.android.settings.core.PreferenceXmlParserUtils.METADATA_BOOL_SETTING_FIELD; +import static com.android.settings.core.PreferenceXmlParserUtils.METADATA_KEY; + +public class BoolSettingPrefController extends AbstractTogglePrefController + implements ExtSettingPrefController { + private final BoolSetting setting; + private final ExtSettingControllerHelper helper; + + public BoolSettingPrefController(Context ctx, String key, BoolSetting setting) { + this(ctx, key, setting, ctx.getUser()); + } + + public BoolSettingPrefController(Context ctx, String key, BoolSetting setting, UserHandle user) { + super(ctx, key); + this.setting = setting; + Context userContext = ctx.getUser().equals(user) ? ctx : ctx.createContextAsUser(user, 0); + helper = new ExtSettingControllerHelper<>(userContext, setting); + } + + @Override + public int getAvailabilityStatus() { + return helper.getAvailabilityStatus(); + } + + @Override + public final boolean isChecked() { + return setting.get(helper.context); + } + + @Override + public boolean setChecked(boolean isChecked) { + return setting.put(helper.context, isChecked); + } + + @Override + public void onResume(@NonNull LifecycleOwner owner) { + helper.onResume(this); + } + + @Override + public void onPause(@NonNull LifecycleOwner owner) { + helper.onPause(this); + } + + // called by the setting observer + @Override + public void accept(BoolSetting boolSetting) { + if (preference != null) { + updateState(preference); + } + } + + // called when PreferenceScreen XML is parsed + public static void maybeAdd(Context context, Bundle metadata, + List dest) { + String boolSettingField = metadata.getString(METADATA_BOOL_SETTING_FIELD); + if (boolSettingField == null) { + return; + } + String[] split = boolSettingField.split(" "); + + BoolSetting boolSetting; + try { + Class c = Class.forName(split[0]); + Field field = c.getField(split[1]); + boolSetting = (BoolSetting) Objects.requireNonNull(field.get(null)); + } catch (Exception e) { + throw new IllegalStateException("Invalid BoolSetting field " + boolSettingField); + } + + String key = Objects.requireNonNull(metadata.getString(METADATA_KEY)); + + dest.add(new BoolSettingPrefController(context, key, boolSetting)); + } +} diff --git a/src/com/android/settings/ext/ExtSettingControllerHelper.java b/src/com/android/settings/ext/ExtSettingControllerHelper.java new file mode 100644 index 00000000000..1c8e70d4cdb --- /dev/null +++ b/src/com/android/settings/ext/ExtSettingControllerHelper.java @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2023 GrapheneOS + * SPDX-License-Identifier: Apache-2.0 + */ + +package com.android.settings.ext; + +import android.content.ContentResolver; +import android.content.Context; +import android.ext.settings.Setting; +import android.provider.Settings; + +import java.util.function.Consumer; + +import static com.android.settings.core.BasePreferenceController.AVAILABLE; +import static com.android.settings.core.BasePreferenceController.CONDITIONALLY_UNAVAILABLE; +import static com.android.settings.core.BasePreferenceController.DISABLED_FOR_USER; + +public class ExtSettingControllerHelper { + public final Context context; + private final T setting; + + ExtSettingControllerHelper(Context context, T setting) { + this.context = context; + this.setting = setting; + } + + public static int getGlobalSettingAvailability(Context ctx) { + return ctx.getUser().isSystem() ? AVAILABLE : DISABLED_FOR_USER; + } + + public static int getSecondaryUserOnlySettingAvailability(Context ctx) { + return ctx.getUser().isSystem() ? DISABLED_FOR_USER : AVAILABLE; + } + + public static int getDevModeSettingAvailability(Context ctx) { + ContentResolver cr = ctx.getContentResolver(); + String key = Settings.Global.DEVELOPMENT_SETTINGS_ENABLED; + + return (Settings.Global.getInt(cr, key, 0) == 0) ? + CONDITIONALLY_UNAVAILABLE : AVAILABLE; + } + + int getAvailabilityStatus() { + if (setting.getScope() != Setting.Scope.PER_USER) { + return getGlobalSettingAvailability(context); + } + return AVAILABLE; + } + + private Object observer; + + void onResume(ExtSettingPrefController espc) { + registerObserver(espc); + } + + void onPause(ExtSettingPrefController espc) { + unregisterObserver(); + } + + void registerObserver(Consumer settingObserver) { + if (setting.canObserveState()) { + observer = setting.registerObserver(context, context.getMainThreadHandler(), settingObserver); + } + } + + void unregisterObserver() { + if (setting.canObserveState()) { + setting.unregisterObserver(context, observer); + } + } +} diff --git a/src/com/android/settings/ext/ExtSettingPrefController.java b/src/com/android/settings/ext/ExtSettingPrefController.java new file mode 100644 index 00000000000..f641e344b50 --- /dev/null +++ b/src/com/android/settings/ext/ExtSettingPrefController.java @@ -0,0 +1,12 @@ +package com.android.settings.ext; + +import android.ext.settings.Setting; + +import androidx.annotation.NonNull; +import androidx.lifecycle.DefaultLifecycleObserver; +import androidx.lifecycle.LifecycleOwner; + +import java.util.function.Consumer; + +interface ExtSettingPrefController extends DefaultLifecycleObserver, Consumer { +} diff --git a/src/com/android/settings/ext/IntSettingPrefController.java b/src/com/android/settings/ext/IntSettingPrefController.java new file mode 100644 index 00000000000..38ecc9a89b3 --- /dev/null +++ b/src/com/android/settings/ext/IntSettingPrefController.java @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2022 GrapheneOS + * SPDX-License-Identifier: Apache-2.0 + */ + +package com.android.settings.ext; + +import android.content.Context; +import android.ext.settings.IntSetting; +import android.os.UserHandle; + +import androidx.annotation.NonNull; +import androidx.lifecycle.LifecycleOwner; + +public abstract class IntSettingPrefController extends AbstractListPreferenceController + implements ExtSettingPrefController +{ + private final IntSetting setting; + private final ExtSettingControllerHelper helper; + + protected IntSettingPrefController(Context ctx, String key, IntSetting setting) { + this(ctx, key, setting, ctx.getUser()); + } + + protected IntSettingPrefController(Context ctx, String key, IntSetting setting, UserHandle user) { + super(ctx, key); + this.setting = setting; + Context userContext = ctx.getUser().equals(user) ? ctx : ctx.createContextAsUser(user, 0); + helper = new ExtSettingControllerHelper<>(userContext, setting); + } + + @Override + public int getAvailabilityStatus() { + return helper.getAvailabilityStatus(); + } + + @Override + protected final int getCurrentValue() { + return setting.get(helper.context); + } + + @Override + protected boolean setValue(int val) { + return setting.put(helper.context, val); + } + + @Override + public void onResume(@NonNull LifecycleOwner owner) { + helper.onResume(this); + } + + @Override + public void onPause(@NonNull LifecycleOwner owner) { + helper.onPause(this); + } + + // called by the setting observer + @Override + public void accept(IntSetting intSetting) { + updatePreference(); + } +} From eb443dbb92526a82261f46781e265c92b1250349 Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Tue, 30 Jul 2024 15:20:39 +0300 Subject: [PATCH 008/162] add Exploit protection screen --- AndroidManifest.xml | 17 +++++++++++ res/values/strings_ext.xml | 5 ++++ res/xml/exploit_protection_settings.xml | 16 ++++++++++ src/com/android/settings/Settings.java | 3 ++ .../core/gateway/SettingsGateway.java | 1 + .../dashboard/DashboardFragmentRegistry.java | 3 ++ .../ExploitProtectionFragment.java | 29 +++++++++++++++++++ 7 files changed, 74 insertions(+) create mode 100644 res/xml/exploit_protection_settings.xml create mode 100644 src/com/android/settings/safetycenter/ExploitProtectionFragment.java diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 585c2125164..49d0b5905bc 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -2407,6 +2407,23 @@ android:value="@string/menu_key_safety_center"/> + + + + + + + + + + + Enabled Disabled + Exploit protection + + App exploit protection + + diff --git a/res/xml/exploit_protection_settings.xml b/res/xml/exploit_protection_settings.xml new file mode 100644 index 00000000000..54da29f1394 --- /dev/null +++ b/res/xml/exploit_protection_settings.xml @@ -0,0 +1,16 @@ + + + + + + + + + + diff --git a/src/com/android/settings/Settings.java b/src/com/android/settings/Settings.java index 76d8f1667d9..15db565117d 100644 --- a/src/com/android/settings/Settings.java +++ b/src/com/android/settings/Settings.java @@ -629,6 +629,9 @@ public static class ContactsStorageSettingsActivity extends SettingsActivity { / public static class ContentProtectionSettingsActivity extends SettingsActivity { /* empty */ } public static class MagnificationActivity extends SettingsActivity { /* empty */ } public static class FlashNotificationsActivity extends SettingsActivity { /* empty */ } + + public static class ExploitProtectionActivity extends SettingsActivity {} + public static class NotificationBundlesActivity extends SettingsActivity { /* empty */ } public static class NotificationSummarizationActivity extends SettingsActivity { /* empty */ } diff --git a/src/com/android/settings/core/gateway/SettingsGateway.java b/src/com/android/settings/core/gateway/SettingsGateway.java index 4b86248264a..2d3f63e9a5e 100644 --- a/src/com/android/settings/core/gateway/SettingsGateway.java +++ b/src/com/android/settings/core/gateway/SettingsGateway.java @@ -229,6 +229,7 @@ public class SettingsGateway { * security exception if the fragment it needs to display is not in this list. */ public static final String[] ENTRY_FRAGMENTS = { + com.android.settings.safetycenter.ExploitProtectionFragment.class.getName(), AdvancedConnectedDeviceDashboardFragment.class.getName(), CreateShortcut.class.getName(), BluetoothPairingDetail.class.getName(), diff --git a/src/com/android/settings/dashboard/DashboardFragmentRegistry.java b/src/com/android/settings/dashboard/DashboardFragmentRegistry.java index 26a1f7ff63f..f93c417c89a 100644 --- a/src/com/android/settings/dashboard/DashboardFragmentRegistry.java +++ b/src/com/android/settings/dashboard/DashboardFragmentRegistry.java @@ -42,6 +42,7 @@ import com.android.settings.notification.ConfigureNotificationSettings; import com.android.settings.notification.SoundSettings; import com.android.settings.privacy.PrivacyDashboardFragment; +import com.android.settings.safetycenter.ExploitProtectionFragment; import com.android.settings.safetycenter.MoreSecurityPrivacyFragment; import com.android.settings.safetycenter.ui.PrivacyControlsFragment; import com.android.settings.security.LockscreenDashboardFragment; @@ -73,6 +74,8 @@ public class DashboardFragmentRegistry { static { PARENT_TO_CATEGORY_KEY_MAP = new ArrayMap<>(); + PARENT_TO_CATEGORY_KEY_MAP.put(ExploitProtectionFragment.class.getName(), + CategoryKey.CATEGORY_EXPLOIT_PROTECTION_SETTINGS); PARENT_TO_CATEGORY_KEY_MAP.put(TopLevelSettings.class.getName(), CategoryKey.CATEGORY_HOMEPAGE); PARENT_TO_CATEGORY_KEY_MAP.put( diff --git a/src/com/android/settings/safetycenter/ExploitProtectionFragment.java b/src/com/android/settings/safetycenter/ExploitProtectionFragment.java new file mode 100644 index 00000000000..2542012590b --- /dev/null +++ b/src/com/android/settings/safetycenter/ExploitProtectionFragment.java @@ -0,0 +1,29 @@ +package com.android.settings.safetycenter; + +import com.android.settings.R; +import com.android.settings.dashboard.DashboardFragment; +import com.android.settings.search.BaseSearchIndexProvider; +import com.android.settingslib.search.SearchIndexable; + +@SearchIndexable +public class ExploitProtectionFragment extends DashboardFragment { + private static final String TAG = "ExploitProtFragment"; + + @Override + protected int getPreferenceScreenResId() { + return R.xml.exploit_protection_settings; + } + + @Override + public int getMetricsCategory() { + return METRICS_CATEGORY_UNKNOWN; + } + + @Override + protected String getLogTag() { + return TAG; + } + + public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = + new BaseSearchIndexProvider(R.xml.exploit_protection_settings); +} From 8df8abf0241fd618d9dcc59ad744290414ea8839 Mon Sep 17 00:00:00 2001 From: flawedworld <38294951+flawedworld@users.noreply.github.com> Date: Tue, 6 Apr 2021 01:13:36 +0100 Subject: [PATCH 009/162] add device info field with bootloader version --- res/values/strings.xml | 2 ++ res/xml/firmware_version.xml | 9 ++++++ ...BootloaderVersionPreferenceController.java | 28 +++++++++++++++++++ 3 files changed, 39 insertions(+) create mode 100644 src/com/android/settings/deviceinfo/firmwareversion/BootloaderVersionPreferenceController.java diff --git a/res/values/strings.xml b/res/values/strings.xml index ea5dbdff62b..d438f13354e 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -3624,6 +3624,8 @@ Baseband version + Bootloader version + Kernel version Build number diff --git a/res/xml/firmware_version.xml b/res/xml/firmware_version.xml index edc910b36cf..cf9779a6988 100644 --- a/res/xml/firmware_version.xml +++ b/res/xml/firmware_version.xml @@ -46,6 +46,15 @@ settings:enableCopying="true" settings:controller="com.android.settings.deviceinfo.firmwareversion.BasebandVersionPreferenceController"/> + + + Date: Mon, 19 Jul 2021 01:31:27 +0200 Subject: [PATCH 010/162] hide pattern screenlock option --- .../android/settings/password/ChooseLockGenericController.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/com/android/settings/password/ChooseLockGenericController.java b/src/com/android/settings/password/ChooseLockGenericController.java index cd9eb2fd44d..48dc2094d50 100644 --- a/src/com/android/settings/password/ChooseLockGenericController.java +++ b/src/com/android/settings/password/ChooseLockGenericController.java @@ -175,8 +175,9 @@ public boolean isScreenLockVisible(ScreenLockType type) { && !managedProfile; // Swipe doesn't make sense for profiles. case MANAGED: return mManagedPasswordProvider.isManagedPasswordChoosable(); - case PIN: case PATTERN: + return false; + case PIN: case PASSWORD: // Hide the secure lock screen options if the device doesn't support the secure lock // screen feature. From 6284e7c908cdedd9d25e474fd2483d0021553996 Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Sun, 25 Jul 2021 14:44:48 -0400 Subject: [PATCH 011/162] drop support for showing nearby devices from Play --- res/values/config.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/values/config.xml b/res/values/config.xml index 76a9050bdd0..8c21fe4ed73 100644 --- a/res/values/config.xml +++ b/res/values/config.xml @@ -524,7 +524,7 @@ false - content://com.google.android.gms.nearby.fastpair/device_status_list_item + From bfdf3e21eb2e3328475fa8e5461fad0fde91945f Mon Sep 17 00:00:00 2001 From: Your Name Date: Mon, 18 Oct 2021 02:17:56 +0000 Subject: [PATCH 012/162] Dark mode support for app installation restriction icon --- res/drawable/ic_settings_install.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/res/drawable/ic_settings_install.xml b/res/drawable/ic_settings_install.xml index 5bd5e300eae..eefecc242a4 100644 --- a/res/drawable/ic_settings_install.xml +++ b/res/drawable/ic_settings_install.xml @@ -18,7 +18,8 @@ android:width="24dp" android:height="24dp" android:viewportWidth="24" - android:viewportHeight="24"> + android:viewportHeight="24" + android:tint="?android:attr/colorControlNormal"> From 96c9256c23fceb5b7b2b18b7333bf2506d9ccc4d Mon Sep 17 00:00:00 2001 From: Danny Lin Date: Wed, 7 Jul 2021 03:02:05 -0700 Subject: [PATCH 013/162] Add preference for increased touch sensitivity (glove mode) This preference controls the glove mode feature on Pixel devices for increased touch sensitivity without requiring a custom HAL or other device-side code. This is done by using the debug.touch_sensitivity_mode system property, which Settings has permission to change. The user-visible value is persisted in Settings.Secure, while the property is persisted in persist.vendor.touch_sensitivity_mode. Co-authored-by: Diab Neiroukh Squashed with e7264c6b8e2a5b6c234d188467b4ad0fda744530 Change-Id: I86af721fde33226d314d8a44525f310828299a72 --- res/values/config_google.xml | 4 ++ res/values/strings.xml | 4 ++ res/values/strings_google.xml | 6 ++ res/xml/display_settings.xml | 6 ++ .../TouchSensitivityPreferenceController.java | 61 +++++++++++++++++++ 5 files changed, 81 insertions(+) create mode 100644 res/values/config_google.xml create mode 100644 res/values/strings_google.xml create mode 100755 src/com/android/settings/display/TouchSensitivityPreferenceController.java diff --git a/res/values/config_google.xml b/res/values/config_google.xml new file mode 100644 index 00000000000..075926c5209 --- /dev/null +++ b/res/values/config_google.xml @@ -0,0 +1,4 @@ + + + false + diff --git a/res/values/strings.xml b/res/values/strings.xml index d438f13354e..fc10f765f88 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -3292,6 +3292,10 @@ Camera access is required for Face Detection. Tap to manage permissions for Device Personalization Services Manage permissions + + Increase touch sensitivity + + Improves touch when using screen protectors Night Light diff --git a/res/values/strings_google.xml b/res/values/strings_google.xml new file mode 100644 index 00000000000..6f981f03170 --- /dev/null +++ b/res/values/strings_google.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/res/xml/display_settings.xml b/res/xml/display_settings.xml index 33f328fc819..283077fc949 100644 --- a/res/xml/display_settings.xml +++ b/res/xml/display_settings.xml @@ -182,6 +182,12 @@ android:summary="@string/peak_refresh_rate_summary" settings:controller="com.android.settings.display.PeakRefreshRatePreferenceController"/> + + Date: Fri, 21 Jan 2022 22:05:44 +0200 Subject: [PATCH 014/162] add dynamic link to sandboxed Google Play settings --- res/values/strings_ext.xml | 3 +- res/xml/apps.xml | 13 +++++ .../applications/GmsCompatAppController.java | 48 +++++++++++++++++++ 3 files changed, 63 insertions(+), 1 deletion(-) create mode 100644 src/com/android/settings/applications/GmsCompatAppController.java diff --git a/res/values/strings_ext.xml b/res/values/strings_ext.xml index 3bda9789896..d57deb8a427 100644 --- a/res/values/strings_ext.xml +++ b/res/values/strings_ext.xml @@ -9,5 +9,6 @@ App exploit protection - + Sandboxed Google Play + Sandboxed Google Play (work profile) diff --git a/res/xml/apps.xml b/res/xml/apps.xml index b6874973b22..8233a1f8a72 100644 --- a/res/xml/apps.xml +++ b/res/xml/apps.xml @@ -134,4 +134,17 @@ + + + + diff --git a/src/com/android/settings/applications/GmsCompatAppController.java b/src/com/android/settings/applications/GmsCompatAppController.java new file mode 100644 index 00000000000..32fe7d05e60 --- /dev/null +++ b/src/com/android/settings/applications/GmsCompatAppController.java @@ -0,0 +1,48 @@ +package com.android.settings.applications; + +import android.app.compat.gms.GmsCompat; +import android.content.Context; +import android.content.Intent; +import android.os.UserHandle; +import android.text.TextUtils; + +import androidx.preference.Preference; + +import com.android.internal.gmscompat.GmsCompatApp; +import com.android.internal.gmscompat.GmsInfo; +import com.android.settings.core.BasePreferenceController; + +public class GmsCompatAppController extends BasePreferenceController { + + public GmsCompatAppController(Context context, String key) { + super(context, key); + } + + @Override + public int getAvailabilityStatus() { + UserHandle workProfile = getWorkProfileUser(); + int userId = workProfile != null ? + workProfile.getIdentifier() : + UserHandle.myUserId(); + + return GmsCompat.isEnabledFor(GmsInfo.PACKAGE_GMS_CORE, userId) ? + AVAILABLE : DISABLED_FOR_USER; + } + + @Override + public boolean handlePreferenceTreeClick(Preference preference) { + if (!TextUtils.equals(preference.getKey(), getPreferenceKey())) { + return false; + } + Intent intent = new Intent(GmsCompatApp.PKG_NAME + ".SETTINGS_LINK"); + intent.setPackage(GmsCompatApp.PKG_NAME); + + UserHandle workProfile = getWorkProfileUser(); + if (workProfile != null) { + mContext.startActivityAsUser(intent, workProfile); + } else { + mContext.startActivity(intent); + } + return true; + } +} From 1cf885e2b4a76bd1626f89649ddfcb53248656b8 Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Mon, 12 Aug 2024 17:45:43 +0300 Subject: [PATCH 015/162] add Private Space sandboxed Google Play link It's added to Private Space screen instead of the Apps screen (where regular and work profile links are) to avoid revealing whether the Private Space is present when the "Hide when locked" Private Space option is enabled. --- res/xml/private_space_settings.xml | 5 +++ .../applications/GmsCompatAppController.java | 41 +++++++++++++------ 2 files changed, 34 insertions(+), 12 deletions(-) diff --git a/res/xml/private_space_settings.xml b/res/xml/private_space_settings.xml index e444c80dad3..80a8658df50 100644 --- a/res/xml/private_space_settings.xml +++ b/res/xml/private_space_settings.xml @@ -56,6 +56,11 @@ settings:controller="com.android.settings.privatespace.HidePrivateSpaceSummaryController" settings:searchable="false" /> + + Date: Sat, 5 Mar 2022 17:37:47 +0000 Subject: [PATCH 016/162] Show Hardware SKU in About Phone --- res/values/strings_ext.xml | 1 + res/xml/hardware_info.xml | 9 ++++ .../HardwareSkuPreferenceController.java | 48 +++++++++++++++++++ 3 files changed, 58 insertions(+) create mode 100644 src/com/android/settings/deviceinfo/hardwareinfo/HardwareSkuPreferenceController.java diff --git a/res/values/strings_ext.xml b/res/values/strings_ext.xml index d57deb8a427..8f1e44c30d6 100644 --- a/res/values/strings_ext.xml +++ b/res/values/strings_ext.xml @@ -1,5 +1,6 @@ + Hardware SKU Enable Enabled diff --git a/res/xml/hardware_info.xml b/res/xml/hardware_info.xml index e086a486ee0..8fef9371870 100644 --- a/res/xml/hardware_info.xml +++ b/res/xml/hardware_info.xml @@ -57,4 +57,13 @@ settings:controller="com.android.settings.deviceinfo.hardwareinfo.ManufacturedYearPreferenceController" settings:enableCopying="true"/> + + + diff --git a/src/com/android/settings/deviceinfo/hardwareinfo/HardwareSkuPreferenceController.java b/src/com/android/settings/deviceinfo/hardwareinfo/HardwareSkuPreferenceController.java new file mode 100644 index 00000000000..4be09710e8c --- /dev/null +++ b/src/com/android/settings/deviceinfo/hardwareinfo/HardwareSkuPreferenceController.java @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.deviceinfo.hardwareinfo; + +import android.content.Context; +import android.os.SystemProperties; +import android.text.TextUtils; + +import com.android.settings.R; +import com.android.settings.core.BasePreferenceController; +import com.android.settings.slices.Sliceable; + +public class HardwareSkuPreferenceController extends BasePreferenceController { + + public HardwareSkuPreferenceController(Context context, String preferenceKey) { + super(context, preferenceKey); + } + + @Override + public int getAvailabilityStatus() { + return mContext.getResources().getBoolean(R.bool.config_show_device_model) && + !TextUtils.isEmpty(getSummary()) ? AVAILABLE : UNSUPPORTED_ON_DEVICE; + } + + @Override + public boolean useDynamicSliceSummary() { + return true; + } + + @Override + public CharSequence getSummary() { + return SystemProperties.get("ro.boot.hardware.sku"); + } +} From 4617efe1bfe5828293598beead168a9ff2a73a03 Mon Sep 17 00:00:00 2001 From: Roman Royer Date: Wed, 4 May 2016 19:04:36 -0700 Subject: [PATCH 017/162] Allow sorting Applications by size Allow sorting applications by size in Settings->Apps just like in Settings->Storage/USB->Apps Change-Id: I9e022162110e1feff20f257992086e66735e0f5e --- .../applications/manageapplications/ManageApplications.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/com/android/settings/applications/manageapplications/ManageApplications.java b/src/com/android/settings/applications/manageapplications/ManageApplications.java index 9e1cb8d067c..c5f3cd9dd58 100644 --- a/src/com/android/settings/applications/manageapplications/ManageApplications.java +++ b/src/com/android/settings/applications/manageapplications/ManageApplications.java @@ -880,9 +880,11 @@ void updateOptionsMenu() { } mOptionsMenu.findItem(R.id.advanced).setVisible(false); - mOptionsMenu.findItem(R.id.sort_order_alpha).setVisible(mListType == LIST_TYPE_STORAGE + mOptionsMenu.findItem(R.id.sort_order_alpha).setVisible( + (mListType == LIST_TYPE_STORAGE || mListType == LIST_TYPE_MAIN) && mSortOrder != R.id.sort_order_alpha); - mOptionsMenu.findItem(R.id.sort_order_size).setVisible(mListType == LIST_TYPE_STORAGE + mOptionsMenu.findItem(R.id.sort_order_size).setVisible( + (mListType == LIST_TYPE_STORAGE || mListType == LIST_TYPE_MAIN) && mSortOrder != R.id.sort_order_size); mOptionsMenu.findItem(R.id.show_system).setVisible(!mShowSystem From e8cbc6fa7259bfb917c34756e2ae3c0a00e263dd Mon Sep 17 00:00:00 2001 From: June Date: Wed, 16 Mar 2022 07:09:46 +0200 Subject: [PATCH 018/162] add a per-user setting for forwarding censored notifs Signed-off-by: June Co-authored-by: inthewaves Co-authored-by: June --- res/values/strings_ext.xml | 3 + res/xml/user_settings.xml | 6 ++ ...ionsToCurrentUserPreferenceController.java | 60 +++++++++++++++++++ .../android/settings/users/UserSettings.java | 19 ++++++ 4 files changed, 88 insertions(+) create mode 100644 src/com/android/settings/users/SendCensoredNotificationsToCurrentUserPreferenceController.java diff --git a/res/values/strings_ext.xml b/res/values/strings_ext.xml index 8f1e44c30d6..34df22b18f1 100644 --- a/res/values/strings_ext.xml +++ b/res/values/strings_ext.xml @@ -12,4 +12,7 @@ Sandboxed Google Play Sandboxed Google Play (work profile) + + Send notifications to current user + Your lock screen notifications will be forwarded to the current user if you are active in the background. Only the user\'s name, the app\'s name, and the time received will be shown. diff --git a/res/xml/user_settings.xml b/res/xml/user_settings.xml index ec0e72818b1..413091d5cab 100644 --- a/res/xml/user_settings.xml +++ b/res/xml/user_settings.xml @@ -112,4 +112,10 @@ android:fragment="com.android.settings.users.TimeoutToDockUserSettings" settings:controller="com.android.settings.users.TimeoutToDockUserPreferenceController"/> + + diff --git a/src/com/android/settings/users/SendCensoredNotificationsToCurrentUserPreferenceController.java b/src/com/android/settings/users/SendCensoredNotificationsToCurrentUserPreferenceController.java new file mode 100644 index 00000000000..637d7bbb782 --- /dev/null +++ b/src/com/android/settings/users/SendCensoredNotificationsToCurrentUserPreferenceController.java @@ -0,0 +1,60 @@ +package com.android.settings.users; + +import android.content.Context; +import android.provider.Settings; +import android.widget.Toast; + +import androidx.annotation.VisibleForTesting; +import androidx.preference.Preference; + +import com.android.settings.R; +import com.android.settings.core.TogglePreferenceController; + +public class SendCensoredNotificationsToCurrentUserPreferenceController + extends TogglePreferenceController { + private final UserCapabilities mUserCaps; + + public SendCensoredNotificationsToCurrentUserPreferenceController(Context context, String key) { + super(context, key); + mUserCaps = UserCapabilities.create(context); + } + + @Override + public void updateState(Preference preference) { + super.updateState(preference); + mUserCaps.updateAddUserCapabilities(mContext); + if (!isAvailable()) { + preference.setVisible(false); + } else { + preference.setVisible(mUserCaps.mUserSwitcherEnabled); + } + } + + @Override + public int getAvailabilityStatus() { + return mUserCaps.mUserSwitcherEnabled ? AVAILABLE : CONDITIONALLY_UNAVAILABLE; + } + + @Override + public boolean isChecked() { + return Settings.Secure.getInt(mContext.getContentResolver(), + Settings.Secure.SEND_CENSORED_NOTIFICATIONS_TO_CURRENT_USER, 0) != 0; + } + + @Override + public boolean setChecked(boolean isChecked) { + return Settings.Secure.putInt(mContext.getContentResolver(), + Settings.Secure.SEND_CENSORED_NOTIFICATIONS_TO_CURRENT_USER, isChecked ? 1 : 0); + } + + @Override + public CharSequence getSummary() { + return mContext.getString( + R.string.user_settings_send_censored_notifications_to_current_summary); + } + + @Override + public int getSliceHighlightMenuRes() { + return R.string.menu_key_system; + } +} diff --git a/src/com/android/settings/users/UserSettings.java b/src/com/android/settings/users/UserSettings.java index d1186a52244..07053db27f2 100644 --- a/src/com/android/settings/users/UserSettings.java +++ b/src/com/android/settings/users/UserSettings.java @@ -149,6 +149,8 @@ public class UserSettings extends SettingsPreferenceFragment private static final String KEY_GUEST_USER_CATEGORY = "guest_user_category"; private static final String KEY_ALLOW_MULTIPLE_USERS = "allow_multiple_users"; private static final String KEY_USER_SETTINGS_SCREEN = "user_settings_screen"; + private static final String KEY_SEND_CENSORED_NOTIFICATIONS = + "user_settings_send_censored_notifications_to_current"; private static final String KEY_USER_SWITCH_TOGGLE = "multiple_users_main_switch"; private static final String SETTING_GUEST_HAS_LOGGED_IN = "systemui.guest_has_logged_in"; @@ -249,6 +251,7 @@ public class UserSettings extends SettingsPreferenceFragment private AddUserFromSignInPreferenceController mAddUserFromSignInPreferenceController; private GuestTelephonyPreferenceController mGuestTelephonyPreferenceController; private RemoveGuestOnExitPreferenceController mRemoveGuestOnExitPreferenceController; + private SendCensoredNotificationsToCurrentUserPreferenceController mSendCensoredNotificationsToCurrentUserPreferenceController; private MultiUserTopIntroPreferenceController mMultiUserTopIntroPreferenceController; private TimeoutToDockUserPreferenceController mTimeoutToDockUserPreferenceController; private UserCreatingDialog mUserCreatingDialog; @@ -341,6 +344,10 @@ public void onCreate(Bundle icicle) { mRemoveGuestOnExitPreferenceController = new RemoveGuestOnExitPreferenceController( activity, KEY_REMOVE_GUEST_ON_EXIT, this, mHandler); + mSendCensoredNotificationsToCurrentUserPreferenceController = + new SendCensoredNotificationsToCurrentUserPreferenceController(activity, + KEY_SEND_CENSORED_NOTIFICATIONS); + mMultiUserTopIntroPreferenceController = new MultiUserTopIntroPreferenceController(activity, KEY_MULTIUSER_TOP_INTRO); @@ -355,6 +362,7 @@ public void onCreate(Bundle icicle) { mAddUserFromSignInPreferenceController.displayPreference(screen); mGuestTelephonyPreferenceController.displayPreference(screen); mRemoveGuestOnExitPreferenceController.displayPreference(screen); + mSendCensoredNotificationsToCurrentUserPreferenceController.displayPreference(screen); mMultiUserTopIntroPreferenceController.displayPreference(screen); mTimeoutToDockUserPreferenceController.displayPreference(screen); mMainSwitchController.displayPreference(screen); @@ -362,6 +370,8 @@ public void onCreate(Bundle icicle) { screen.findPreference(mAddUserWhenLockedPreferenceController.getPreferenceKey()) .setOnPreferenceChangeListener(mAddUserWhenLockedPreferenceController); + screen.findPreference(mSendCensoredNotificationsToCurrentUserPreferenceController.getPreferenceKey()) + .setOnPreferenceChangeListener(mSendCensoredNotificationsToCurrentUserPreferenceController); screen.findPreference(mAddUserFromSignInPreferenceController.getPreferenceKey()) .setOnPreferenceChangeListener(mAddUserFromSignInPreferenceController); @@ -453,6 +463,9 @@ public void onResume() { mRemoveGuestOnExitPreferenceController.updateState(screen.findPreference( mRemoveGuestOnExitPreferenceController.getPreferenceKey())); mMainSwitchController.updateState(); + mSendCensoredNotificationsToCurrentUserPreferenceController.updateState(screen.findPreference( + mSendCensoredNotificationsToCurrentUserPreferenceController.getPreferenceKey())); + if (mShouldUpdateUserList) { updateUI(); } @@ -1425,6 +1438,10 @@ && getPrefContext() mGuestTelephonyPreferenceController.getPreferenceKey()); mGuestTelephonyPreferenceController.updateState(guestCallPreference); + final Preference sendCensoredNotifs = getPreferenceScreen().findPreference( + mSendCensoredNotificationsToCurrentUserPreferenceController.getPreferenceKey()); + mSendCensoredNotificationsToCurrentUserPreferenceController.updateState(sendCensoredNotifs); + final Preference multiUserTopIntroPreference = getPreferenceScreen().findPreference( mMultiUserTopIntroPreferenceController.getPreferenceKey()); mMultiUserTopIntroPreferenceController.updateState(multiUserTopIntroPreference); @@ -1995,6 +2012,8 @@ public List getNonIndexableKeysFromXml(Context context, int xmlResId, new AddUserWhenLockedPreferenceController( context, KEY_ADD_USER_WHEN_LOCKED); controller.updateNonIndexableKeys(niks); + new SendCensoredNotificationsToCurrentUserPreferenceController(context, + KEY_SEND_CENSORED_NOTIFICATIONS).updateNonIndexableKeys(niks); new AutoSyncDataPreferenceController(context, null /* parent */) .updateNonIndexableKeys(niks); new AutoSyncPersonalDataPreferenceController(context, null /* parent */) From 1850f7c857b803c9c4af18c46483919d6092563e Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Wed, 17 Aug 2022 12:40:26 -0400 Subject: [PATCH 019/162] fully enable location indicators by default --- .../location/RecentLocationAccessPreferenceController.java | 6 +++--- .../location/RecentLocationAccessSeeAllFragment.java | 6 +++--- .../RecentLocationAccessSeeAllPreferenceController.java | 4 ++-- .../location/RecentLocationRequestPreferenceController.java | 4 ++-- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/com/android/settings/location/RecentLocationAccessPreferenceController.java b/src/com/android/settings/location/RecentLocationAccessPreferenceController.java index c93b450ba01..7cfcbe55c9d 100644 --- a/src/com/android/settings/location/RecentLocationAccessPreferenceController.java +++ b/src/com/android/settings/location/RecentLocationAccessPreferenceController.java @@ -53,7 +53,7 @@ public class RecentLocationAccessPreferenceController extends LocationBasePrefer RecentAppOpsAccess mRecentLocationApps; private PreferenceCategory mCategoryRecentLocationRequests; private int mType = ProfileSelectFragment.ProfileType.ALL; - private boolean mShowSystem = false; + private boolean mShowSystem = true; private boolean mSystemSettingChanged = false; @VisibleForTesting @@ -108,9 +108,9 @@ public RecentLocationAccessPreferenceController(Context context, String key, super(context, key); mRecentLocationApps = recentLocationApps; mShowSystem = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_PRIVACY, - SystemUiDeviceConfigFlags.PROPERTY_LOCATION_INDICATORS_SMALL_ENABLED, false) + SystemUiDeviceConfigFlags.PROPERTY_LOCATION_INDICATORS_SMALL_ENABLED, true) ? Settings.Secure.getInt(mContext.getContentResolver(), - Settings.Secure.LOCATION_SHOW_SYSTEM_OPS, 0) == 1 + Settings.Secure.LOCATION_SHOW_SYSTEM_OPS, 1) == 1 : false; } diff --git a/src/com/android/settings/location/RecentLocationAccessSeeAllFragment.java b/src/com/android/settings/location/RecentLocationAccessSeeAllFragment.java index 0ea9ffbdacb..b45bca51c4f 100644 --- a/src/com/android/settings/location/RecentLocationAccessSeeAllFragment.java +++ b/src/com/android/settings/location/RecentLocationAccessSeeAllFragment.java @@ -40,7 +40,7 @@ public class RecentLocationAccessSeeAllFragment extends DashboardFragment { private static final int MENU_SHOW_SYSTEM = Menu.FIRST + 1; private static final int MENU_HIDE_SYSTEM = Menu.FIRST + 2; - private boolean mShowSystem = false; + private boolean mShowSystem = true; private MenuItem mShowSystemMenu; private MenuItem mHideSystemMenu; private RecentLocationAccessSeeAllPreferenceController mController; @@ -61,9 +61,9 @@ public void onAttach(Context context) { public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mShowSystem = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_PRIVACY, - SystemUiDeviceConfigFlags.PROPERTY_LOCATION_INDICATORS_SMALL_ENABLED, false) + SystemUiDeviceConfigFlags.PROPERTY_LOCATION_INDICATORS_SMALL_ENABLED, true) ? Settings.Secure.getInt(getContentResolver(), - Settings.Secure.LOCATION_SHOW_SYSTEM_OPS, 0) == 1 + Settings.Secure.LOCATION_SHOW_SYSTEM_OPS, 1) == 1 : false; } diff --git a/src/com/android/settings/location/RecentLocationAccessSeeAllPreferenceController.java b/src/com/android/settings/location/RecentLocationAccessSeeAllPreferenceController.java index 50c105b44c5..6eb1402b413 100644 --- a/src/com/android/settings/location/RecentLocationAccessSeeAllPreferenceController.java +++ b/src/com/android/settings/location/RecentLocationAccessSeeAllPreferenceController.java @@ -57,11 +57,11 @@ public RecentLocationAccessSeeAllPreferenceController(Context context, String ke DeviceConfig.NAMESPACE_PRIVACY, SystemUiDeviceConfigFlags .PROPERTY_LOCATION_INDICATORS_SMALL_ENABLED, - false) + true) ? Settings.Secure.getInt( mContext.getContentResolver(), Settings.Secure.LOCATION_SHOW_SYSTEM_OPS, - 0) + 1) == 1 : false; diff --git a/src/com/android/settings/location/RecentLocationRequestPreferenceController.java b/src/com/android/settings/location/RecentLocationRequestPreferenceController.java index 39211ee5202..bee904efdc4 100644 --- a/src/com/android/settings/location/RecentLocationRequestPreferenceController.java +++ b/src/com/android/settings/location/RecentLocationRequestPreferenceController.java @@ -87,9 +87,9 @@ public void displayPreference(PreferenceScreen screen) { final List recentLocationRequests = new ArrayList<>(); final UserManager userManager = UserManager.get(mContext); final boolean showSystem = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_PRIVACY, - SystemUiDeviceConfigFlags.PROPERTY_LOCATION_INDICATORS_SMALL_ENABLED, false) + SystemUiDeviceConfigFlags.PROPERTY_LOCATION_INDICATORS_SMALL_ENABLED, true) ? Settings.Secure.getInt(mContext.getContentResolver(), - Settings.Secure.LOCATION_SHOW_SYSTEM_OPS, 0) == 1 + Settings.Secure.LOCATION_SHOW_SYSTEM_OPS, 1) == 1 : false; for (RecentLocationApps.Request request : mRecentLocationApps.getAppListSorted( From f2c7aa6920584dbe25cccf7994821dc1d5bec5e5 Mon Sep 17 00:00:00 2001 From: Pratyush Date: Fri, 19 Aug 2022 11:05:36 +0530 Subject: [PATCH 020/162] LTE Only Mode Co-authored-by: inthewaves Squashed with: Fix LTE Only mode on World Mode Co-authored-by: flawedworld --- res/values/strings.xml | 6 +++++ ...nabledNetworkModePreferenceController.java | 24 ++++++++++++++++++- ...ferredNetworkModePreferenceController.java | 2 +- 3 files changed, 30 insertions(+), 2 deletions(-) diff --git a/res/values/strings.xml b/res/values/strings.xml index fc10f765f88..046f7762bcb 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -12890,6 +12890,8 @@ Preferred network mode: CDMA/EvDo/GSM/WCDMA Preferred network mode: LTE + + Preferred network mode: LTE only Preferred network mode: GSM/WCDMA/LTE @@ -12955,8 +12957,12 @@ 4G LTE (recommended) + + LTE only 4G (recommended) + + 4G only 3G diff --git a/src/com/android/settings/network/telephony/EnabledNetworkModePreferenceController.java b/src/com/android/settings/network/telephony/EnabledNetworkModePreferenceController.java index 932897ec20d..c3b7f3b780c 100644 --- a/src/com/android/settings/network/telephony/EnabledNetworkModePreferenceController.java +++ b/src/com/android/settings/network/telephony/EnabledNetworkModePreferenceController.java @@ -144,7 +144,7 @@ public EnabledNetworkModePreferenceController(Context context, String key) { @Override public int getAvailabilityStatus() { return getNetworkModePreferenceType(mContext, mSubId) - == NetworkModePreferenceType.EnabledNetworkMode + != NetworkModePreferenceType.PreferredNetworkMode ? AVAILABLE : CONDITIONALLY_UNAVAILABLE; } @@ -385,6 +385,7 @@ private boolean isDisabledByAdmin() { } void setPreferenceEntries() { + boolean lteOnlyUnsupported = false; mTelephonyManager = mTelephonyManager.createForSubscriptionId(mSubId); clearAllEntries(); @@ -400,6 +401,7 @@ void setPreferenceEntries() { .addFormat(UiOptions.PresentFormat.addGlobalEntry); break; case ENABLED_NETWORKS_CDMA_NO_LTE_CHOICES: + lteOnlyUnsupported = true; uiOptions = uiOptions .setChoices(R.array.enabled_networks_cdma_no_lte_values) .addFormat(UiOptions.PresentFormat.add3gEntry) @@ -419,6 +421,7 @@ void setPreferenceEntries() { .addFormat(UiOptions.PresentFormat.add2gEntry); break; case ENABLED_NETWORKS_EXCEPT_GSM_LTE_CHOICES: + lteOnlyUnsupported = true; uiOptions = uiOptions .setChoices(R.array.enabled_networks_except_gsm_lte_values) .addFormat(UiOptions.PresentFormat.add3gEntry); @@ -436,6 +439,7 @@ void setPreferenceEntries() { .addFormat(UiOptions.PresentFormat.add3gEntry); break; case ENABLED_NETWORKS_EXCEPT_LTE_CHOICES: + lteOnlyUnsupported = true; uiOptions = uiOptions .setChoices(R.array.enabled_networks_except_lte_values) .addFormat(UiOptions.PresentFormat.add3gEntry) @@ -484,6 +488,11 @@ void setPreferenceEntries() { throw new IllegalArgumentException( uiOptions.getType().name() + " index error."); } + + if (!lteOnlyUnsupported) { + addLteOnlyEntry(); + } + // Compose options based on given values and formats. IntStream.range(0, formatList.size()).forEach(entryIndex -> { switch (formatList.get(entryIndex)) { @@ -667,6 +676,9 @@ void setPreferenceValueAndSummary(int networkMode) { break; } case TelephonyManager.NETWORK_MODE_LTE_ONLY: + setSummary(mShow4gForLTE + ? R.string.network_4G_only : R.string.network_lte_only); + break; case TelephonyManager.NETWORK_MODE_LTE_WCDMA: if (!mIsGlobalCdma) { setSelectedEntry(TelephonyManager.NETWORK_MODE_LTE_GSM_WCDMA); @@ -858,6 +870,16 @@ private void add1xEntry(int value) { mEntriesValue.add(value); } + private void addLteOnlyEntry() { + if (mShow4gForLTE) { + mEntries.add(mContext.getString(R.string.network_4G_only)); + mEntriesValue.add(TelephonyManager.NETWORK_MODE_LTE_ONLY); + } else { + mEntries.add(mContext.getString(R.string.network_lte_only)); + mEntriesValue.add(TelephonyManager.NETWORK_MODE_LTE_ONLY); + } + } + private void addCustomEntry(String name, int value) { mEntries.add(name); mEntriesValue.add(value); diff --git a/src/com/android/settings/network/telephony/PreferredNetworkModePreferenceController.java b/src/com/android/settings/network/telephony/PreferredNetworkModePreferenceController.java index 1ee1b31e4dd..d70b1ed8b7e 100644 --- a/src/com/android/settings/network/telephony/PreferredNetworkModePreferenceController.java +++ b/src/com/android/settings/network/telephony/PreferredNetworkModePreferenceController.java @@ -220,7 +220,7 @@ private int getPreferredNetworkModeSummaryResId(int networkMode) { case TelephonyManager.NETWORK_MODE_LTE_TDSCDMA: return R.string.preferred_network_mode_lte_tdscdma_summary; case TelephonyManager.NETWORK_MODE_LTE_ONLY: - return R.string.preferred_network_mode_lte_summary; + return R.string.preferred_network_mode_lte_only_summary; case TelephonyManager.NETWORK_MODE_LTE_TDSCDMA_GSM: return R.string.preferred_network_mode_lte_tdscdma_gsm_summary; case TelephonyManager.NETWORK_MODE_LTE_TDSCDMA_GSM_WCDMA: From cd316ca0578ef74836feb904b9ab6497b7b875c9 Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Sun, 13 Nov 2022 20:24:05 +0200 Subject: [PATCH 021/162] battery usage UI: use a fallback name for unknown components --- .../fuelgauge/batteryusage/BatteryEntry.java | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryEntry.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryEntry.java index fef30563fe2..6b057484c9f 100644 --- a/src/com/android/settings/fuelgauge/batteryusage/BatteryEntry.java +++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryEntry.java @@ -616,14 +616,10 @@ public static NameAndIcon getNameAndIconFromPowerComponent( iconId = R.drawable.ic_settings_aod; break; default: - Log.w( - TAG, - "unknown attribute:" - + DebugUtils.constantToString( - BatteryConsumer.class, - "POWER_COMPONENT_", - powerComponentId)); - name = null; + String fieldName = DebugUtils.constantToString( + BatteryConsumer.class, "POWER_COMPONENT_", powerComponentId); + Log.w(TAG, "unknown attribute:" + fieldName); + name = context.getResources().getString(R.string.header_category_system) + " (" + fieldName + ")"; iconId = R.drawable.ic_power_system; break; } From 7a3b6ded29286caa8bac48dc676b625d00ecc21d Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Tue, 14 Feb 2023 10:05:57 +0200 Subject: [PATCH 022/162] add a toggle for auto-grants of OTHER_SENSORS permission --- res/values/strings_ext.xml | 5 +++++ res/xml/more_security_privacy_settings.xml | 7 +++++++ 2 files changed, 12 insertions(+) diff --git a/res/values/strings_ext.xml b/res/values/strings_ext.xml index 34df22b18f1..f8173a12a79 100644 --- a/res/values/strings_ext.xml +++ b/res/values/strings_ext.xml @@ -15,4 +15,9 @@ Send notifications to current user Your lock screen notifications will be forwarded to the current user if you are active in the background. Only the user\'s name, the app\'s name, and the time received will be shown. + + Allow Sensors permission to apps by default + Sensors is a non-standard permission, apps may malfunction if it’s denied. + A permission prompt will be shown when an app tries to access sensors. Note that some apps may need to be manually restarted after allowing the Sensors permission. + diff --git a/res/xml/more_security_privacy_settings.xml b/res/xml/more_security_privacy_settings.xml index 0068872ef31..3f95584f381 100644 --- a/res/xml/more_security_privacy_settings.xml +++ b/res/xml/more_security_privacy_settings.xml @@ -97,6 +97,13 @@ settings:controller= "com.android.settings.sound.MediaControlsLockScreenPreferenceController" /> + + Date: Tue, 14 Feb 2023 10:27:56 +0200 Subject: [PATCH 023/162] add a toggle for camera access from the lock screen --- res/values/strings_ext.xml | 2 ++ res/xml/security_settings_picker.xml | 4 ++++ src/com/android/settings/password/ChooseLockGeneric.java | 4 ++++ 3 files changed, 10 insertions(+) diff --git a/res/values/strings_ext.xml b/res/values/strings_ext.xml index f8173a12a79..60aa5c3db17 100644 --- a/res/values/strings_ext.xml +++ b/res/values/strings_ext.xml @@ -20,4 +20,6 @@ Sensors is a non-standard permission, apps may malfunction if it’s denied. A permission prompt will be shown when an app tries to access sensors. Note that some apps may need to be manually restarted after allowing the Sensors permission. + Allow camera access when locked + diff --git a/res/xml/security_settings_picker.xml b/res/xml/security_settings_picker.xml index f3f3ba42b1b..fac3712e189 100644 --- a/res/xml/security_settings_picker.xml +++ b/res/xml/security_settings_picker.xml @@ -88,6 +88,10 @@ android:title="@string/lockpattern_settings_enhanced_pin_privacy_title" android:summary="@string/lockpattern_settings_enhanced_pin_privacy_summary" /> + Date: Tue, 14 Feb 2023 11:23:29 +0200 Subject: [PATCH 024/162] add auto-reboot setting Squashed with: 20d4d3e46ba4a626d6044df499b91c1fc5e5bd96 514f0ddf2adbb7b69b0750806020476cef8ed17e Co-authored-by: Daniel Micay --- res/values/strings_ext.xml | 3 ++ res/xml/exploit_protection_settings.xml | 5 ++ .../security/AutoRebootPrefController.java | 49 +++++++++++++++++++ 3 files changed, 57 insertions(+) create mode 100644 src/com/android/settings/security/AutoRebootPrefController.java diff --git a/res/values/strings_ext.xml b/res/values/strings_ext.xml index 60aa5c3db17..26a5d59a775 100644 --- a/res/values/strings_ext.xml +++ b/res/values/strings_ext.xml @@ -22,4 +22,7 @@ Allow camera access when locked + Auto reboot + Automatically reboot the device if it hasn\'t been unlocked within the selected duration of time. + diff --git a/res/xml/exploit_protection_settings.xml b/res/xml/exploit_protection_settings.xml index 54da29f1394..faaf3b59180 100644 --- a/res/xml/exploit_protection_settings.xml +++ b/res/xml/exploit_protection_settings.xml @@ -5,6 +5,11 @@ android:key="exploit_protection_settings" android:title="@string/exploit_protection_settings"> + + diff --git a/src/com/android/settings/security/AutoRebootPrefController.java b/src/com/android/settings/security/AutoRebootPrefController.java new file mode 100644 index 00000000000..9c00e954e96 --- /dev/null +++ b/src/com/android/settings/security/AutoRebootPrefController.java @@ -0,0 +1,49 @@ +package com.android.settings.security; + +import android.content.Context; +import android.ext.settings.ExtSettings; + +import androidx.preference.PreferenceScreen; + +import com.android.settings.R; +import com.android.settings.ext.IntSettingPrefController; +import com.android.settings.ext.RadioButtonPickerFragment2; + +import static java.util.concurrent.TimeUnit.DAYS; +import static java.util.concurrent.TimeUnit.HOURS; +import static java.util.concurrent.TimeUnit.MINUTES; + +public class AutoRebootPrefController extends IntSettingPrefController { + + public AutoRebootPrefController(Context ctx, String key) { + super(ctx, key, ExtSettings.AUTO_REBOOT_TIMEOUT); + } + + @Override + public void addPrefsBeforeList(RadioButtonPickerFragment2 fragment, PreferenceScreen screen) { + addFooterPreference(screen, R.string.auto_reboot_footer, + "https://grapheneos.org/features#auto-reboot"); + } + + @Override + protected void getEntries(Entries entries) { + entries.add(R.string.switch_off_text, 0); + entries.add(3, DAYS); + entries.add(2, DAYS); + entries.add(36, HOURS); + entries.add(1, DAYS); + entries.add(18, HOURS); + entries.add(12, HOURS); + entries.add(8, HOURS); + entries.add(4, HOURS); + entries.add(2, HOURS); + entries.add(1, HOURS); + entries.add(30, MINUTES); + entries.add(10, MINUTES); + } + + @Override + protected boolean isCredentialConfirmationRequired() { + return true; + } +} From 9f225b3028c2604898d91de51b7bc7df9882e45f Mon Sep 17 00:00:00 2001 From: r3g_5z Date: Sat, 18 Feb 2023 11:09:31 -0500 Subject: [PATCH 025/162] Add toggle for screenshot timestamp EXIF metadata Signed-off-by: r3g_5z --- res/values/strings_ext.xml | 3 +++ res/xml/more_security_privacy_settings.xml | 6 ++++++ 2 files changed, 9 insertions(+) diff --git a/res/values/strings_ext.xml b/res/values/strings_ext.xml index 26a5d59a775..0c351a59378 100644 --- a/res/values/strings_ext.xml +++ b/res/values/strings_ext.xml @@ -25,4 +25,7 @@ Auto reboot Automatically reboot the device if it hasn\'t been unlocked within the selected duration of time. + Save screenshot timestamp to EXIF + Enables adding a timestamp to screenshot EXIF metadata + diff --git a/res/xml/more_security_privacy_settings.xml b/res/xml/more_security_privacy_settings.xml index 3f95584f381..adf0d09c604 100644 --- a/res/xml/more_security_privacy_settings.xml +++ b/res/xml/more_security_privacy_settings.xml @@ -104,6 +104,12 @@ android:summaryOff="@string/auto_grant_OTHER_SENSORS_permission_summary_off" settings:boolSettingField="android.ext.settings.ExtSettings AUTO_GRANT_OTHER_SENSORS_PERMISSION"/> + + Date: Fri, 3 Mar 2023 09:53:21 +0200 Subject: [PATCH 026/162] add GNSS SUPL setting --- res/values/strings_ext.xml | 8 ++++ res/xml/location_settings.xml | 5 +++ .../location/GnssSuplPrefController.java | 40 +++++++++++++++++++ 3 files changed, 53 insertions(+) create mode 100644 src/com/android/settings/location/GnssSuplPrefController.java diff --git a/res/values/strings_ext.xml b/res/values/strings_ext.xml index 0c351a59378..e9ed237eec9 100644 --- a/res/values/strings_ext.xml +++ b/res/values/strings_ext.xml @@ -28,4 +28,12 @@ Save screenshot timestamp to EXIF Enables adding a timestamp to screenshot EXIF metadata + Secure User Plane Location (SUPL) + A-GNSS (assisted satellite geolocation) based on nearby cell towers. + + GrapheneOS proxy + Standard server + Off + Will make acquiring location lock significantly slower, especially if PSDS is turned off too + diff --git a/res/xml/location_settings.xml b/res/xml/location_settings.xml index 5d5c6b6cd38..c22c22c09a9 100644 --- a/res/xml/location_settings.xml +++ b/res/xml/location_settings.xml @@ -77,6 +77,11 @@ android:title="@string/location_services_preference_title" settings:controller="com.android.settings.location.LocationServicesPreferenceController"/> + + Date: Mon, 16 Oct 2023 09:42:40 -0400 Subject: [PATCH 027/162] disable auto confirm PIN toggle by default --- src/com/android/settings/password/ChooseLockPassword.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/com/android/settings/password/ChooseLockPassword.java b/src/com/android/settings/password/ChooseLockPassword.java index b3d42275fae..184e228d127 100644 --- a/src/com/android/settings/password/ChooseLockPassword.java +++ b/src/com/android/settings/password/ChooseLockPassword.java @@ -1096,9 +1096,6 @@ && isAutoPinConfirmPossible(length) && !isSupervisingProfile()) { mAutoPinConfirmOption.setVisibility(View.VISIBLE); mAutoConfirmSecurityMessage.setVisibility(View.VISIBLE); - if (!mIsAutoPinConfirmOptionSetManually) { - mAutoPinConfirmOption.setChecked(length == MIN_AUTO_PIN_REQUIREMENT_LENGTH); - } } else { mAutoPinConfirmOption.setVisibility(View.GONE); mAutoConfirmSecurityMessage.setVisibility(View.GONE); From 91432a0ded4248388b2802b71b45a6445db38360 Mon Sep 17 00:00:00 2001 From: r3g_5z Date: Wed, 15 Mar 2023 21:11:12 -0400 Subject: [PATCH 028/162] remove missing display resolution lottie animation AOSP does not provide these similar to the missing quickly open camera lottie animation Signed-off-by: r3g_5z --- src/com/android/settings/display/ScreenResolutionFragment.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/com/android/settings/display/ScreenResolutionFragment.java b/src/com/android/settings/display/ScreenResolutionFragment.java index 224a6f3b391..9550a7cb2cd 100644 --- a/src/com/android/settings/display/ScreenResolutionFragment.java +++ b/src/com/android/settings/display/ScreenResolutionFragment.java @@ -107,7 +107,6 @@ protected int getPreferenceScreenResId() { @Override protected void addStaticPreferences(PreferenceScreen screen) { - updateIllustrationImage(mImagePreference); screen.addPreference(mImagePreference); final FooterPreference footerPreference = new FooterPreference(screen.getContext()); @@ -229,7 +228,6 @@ protected boolean setDefaultKey(final String key) { } setDisplayMode(width); - updateIllustrationImage(mImagePreference); return true; } From f222fb0ad75a5803a20aa68b5fbc0eddc8ef5a52 Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Wed, 24 Jan 2024 19:13:22 +0200 Subject: [PATCH 029/162] add toggle for eSIM support via Google's eSIM LPA package --- res/values/strings_ext.xml | 18 +++ res/xml/network_provider_internet.xml | 8 ++ .../network/GoogleEuiccLpaController.java | 108 ++++++++++++++++++ 3 files changed, 134 insertions(+) create mode 100644 src/com/android/settings/network/GoogleEuiccLpaController.java diff --git a/res/values/strings_ext.xml b/res/values/strings_ext.xml index e9ed237eec9..e04ab4c886b 100644 --- a/res/values/strings_ext.xml +++ b/res/values/strings_ext.xml @@ -36,4 +36,22 @@ Off Will make acquiring location lock significantly slower, especially if PSDS is turned off too + eSIM support + +A device restart is required to enable this setting. + + Warning + +"Turning off eSIM support will break the following functionality: + +• adding new eSIMs +• turning existing eSIMs on or off +• removing eSIMs, including from the lock screen (e.g. when eSIM is locked with a forgotten PIN) +• wiping eSIMs during factory reset + +Device will be automatically restarted." + + Restart + Proceed + diff --git a/res/xml/network_provider_internet.xml b/res/xml/network_provider_internet.xml index 7a333672317..d1acf902104 100644 --- a/res/xml/network_provider_internet.xml +++ b/res/xml/network_provider_internet.xml @@ -56,6 +56,14 @@ settings:useAdminDisabledSummary="true" settings:controller="com.android.settings.network.MobileNetworkSummaryController" /> + + setEnabled(isChecked)); + b.show(); + + return false; + } +} From 83715685aaba1859155dc0da6a76b8bb0f186a68 Mon Sep 17 00:00:00 2001 From: r3g_5z Date: Sun, 2 Apr 2023 22:23:41 -0400 Subject: [PATCH 030/162] remote key provisioning server setting Co-authored-by: flawedworld Signed-off-by: r3g_5z --- res/values/strings_ext.xml | 5 +++ res/xml/network_provider_internet.xml | 6 ++++ .../RemoteProvisioningPrefController.java | 36 +++++++++++++++++++ 3 files changed, 47 insertions(+) create mode 100644 src/com/android/settings/network/RemoteProvisioningPrefController.java diff --git a/res/values/strings_ext.xml b/res/values/strings_ext.xml index e04ab4c886b..fc367bb5726 100644 --- a/res/values/strings_ext.xml +++ b/res/values/strings_ext.xml @@ -54,4 +54,9 @@ Device will be automatically restarted." Restart Proceed + Attestation key provisioning + GrapheneOS proxy + Google server + Off + diff --git a/res/xml/network_provider_internet.xml b/res/xml/network_provider_internet.xml index d1acf902104..d04f6999b1c 100644 --- a/res/xml/network_provider_internet.xml +++ b/res/xml/network_provider_internet.xml @@ -126,4 +126,10 @@ android:summary="@string/cellular_security_summary" android:order="30" settings:controller="com.android.settings.network.CellularSecurityPreferenceController"/> + + diff --git a/src/com/android/settings/network/RemoteProvisioningPrefController.java b/src/com/android/settings/network/RemoteProvisioningPrefController.java new file mode 100644 index 00000000000..8617d6bd98c --- /dev/null +++ b/src/com/android/settings/network/RemoteProvisioningPrefController.java @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.network; + +import android.content.Context; +import android.ext.settings.RemoteKeyProvisioningSettings; + +import com.android.settings.R; +import com.android.settings.ext.IntSettingPrefController; + +public class RemoteProvisioningPrefController extends IntSettingPrefController { + + public RemoteProvisioningPrefController(Context ctx, String key) { + super(ctx, key, RemoteKeyProvisioningSettings.SERVER_SETTING); + } + + @Override + protected void getEntries(Entries entries) { + entries.add(R.string.remote_provisioning_enabled_grapheneos_proxy, RemoteKeyProvisioningSettings.GRAPHENEOS_PROXY); + entries.add(R.string.remote_provisioning_enabled_google_server, RemoteKeyProvisioningSettings.STANDARD_SERVER); + } +} From 62200e2b1bcae517e7f275cb3a03975064f67a98 Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Thu, 6 Apr 2023 12:11:09 +0300 Subject: [PATCH 031/162] add toggle for special access to hardware accelerators by Google apps --- res/values/strings_ext.xml | 15 ++++++ res/xml/special_access.xml | 6 +++ ...oogleSpecialAcceleratorAccessFragment.java | 46 +++++++++++++++++++ ...pecialAcceleratorAccessPrefController.java | 34 ++++++++++++++ 4 files changed, 101 insertions(+) create mode 100644 src/com/android/settings/applications/specialaccess/GoogleSpecialAcceleratorAccessFragment.java create mode 100644 src/com/android/settings/applications/specialaccess/GoogleSpecialAcceleratorAccessPrefController.java diff --git a/res/values/strings_ext.xml b/res/values/strings_ext.xml index fc367bb5726..a7d5ff6d9f9 100644 --- a/res/values/strings_ext.xml +++ b/res/values/strings_ext.xml @@ -59,4 +59,19 @@ Device will be automatically restarted." Google server Off + Special access to hardware accelerators for Google apps + Access granted + Access not granted + Grant special access to hardware accelerators to Google apps + +"Some Google apps expect to be able to access hardware accelerators in a special, more capable way than regular apps do. + +Examples of such apps: +• Pixel Camera +• Google Photos +• Google Recorder + +This setting applies to all users on the device." + + diff --git a/res/xml/special_access.xml b/res/xml/special_access.xml index f3a5f3216c7..32867ea63f7 100644 --- a/res/xml/special_access.xml +++ b/res/xml/special_access.xml @@ -231,4 +231,10 @@ android:name="classname" android:value="com.android.settings.Settings$ChangeNfcTagAppsActivity" /> + + diff --git a/src/com/android/settings/applications/specialaccess/GoogleSpecialAcceleratorAccessFragment.java b/src/com/android/settings/applications/specialaccess/GoogleSpecialAcceleratorAccessFragment.java new file mode 100644 index 00000000000..d681703f4cd --- /dev/null +++ b/src/com/android/settings/applications/specialaccess/GoogleSpecialAcceleratorAccessFragment.java @@ -0,0 +1,46 @@ +package com.android.settings.applications.specialaccess; + +import android.app.ActivityThread; +import android.ext.settings.BoolSetting; +import android.ext.settings.ExtSettings; +import android.os.RemoteException; + +import com.android.internal.util.GoogleCameraUtils; +import com.android.settings.R; +import com.android.settings.ext.BoolSettingFragment; +import com.android.settingslib.widget.FooterPreference; + +public class GoogleSpecialAcceleratorAccessFragment extends BoolSettingFragment { + private static final String TAG = GoogleSpecialAcceleratorAccessFragment.class.getSimpleName(); + + @Override + protected BoolSetting getSetting() { + return ExtSettings.ALLOW_GOOGLE_APPS_SPECIAL_ACCESS_TO_ACCELERATORS; + } + + @Override + protected CharSequence getTitle() { + return resText(R.string.Google_apps_special_accelerator_access_title); + } + + @Override + protected CharSequence getMainSwitchTitle() { + return resText(R.string.Google_apps_special_accelerator_access_main_switch); + } + + @Override + protected void onMainSwitchChanged(boolean state) { + if (GoogleCameraUtils.isCustomSeInfoNeededForAccessToAccelerators(requireContext())) { + try { + ActivityThread.getPackageManager().updateSeInfo(GoogleCameraUtils.PACKAGE_NAME); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + } + + @Override + protected FooterPreference makeFooterPref(FooterPreference.Builder builder) { + return builder.setTitle(R.string.Google_apps_special_accelerator_access_footer).build(); + } +} diff --git a/src/com/android/settings/applications/specialaccess/GoogleSpecialAcceleratorAccessPrefController.java b/src/com/android/settings/applications/specialaccess/GoogleSpecialAcceleratorAccessPrefController.java new file mode 100644 index 00000000000..ac7d84fcbb0 --- /dev/null +++ b/src/com/android/settings/applications/specialaccess/GoogleSpecialAcceleratorAccessPrefController.java @@ -0,0 +1,34 @@ +package com.android.settings.applications.specialaccess; + +import android.content.Context; +import android.ext.settings.ExtSettings; + +import com.android.settings.R; +import com.android.settings.ext.BoolSettingFragmentPrefController; + +public class GoogleSpecialAcceleratorAccessPrefController extends BoolSettingFragmentPrefController { + + public GoogleSpecialAcceleratorAccessPrefController(Context ctx, String key) { + super(ctx, key, ExtSettings.ALLOW_GOOGLE_APPS_SPECIAL_ACCESS_TO_ACCELERATORS); + } + + @Override + public int getAvailabilityStatus() { + if (!mContext.getResources().getBoolean( + com.android.internal.R.bool.config_Google_apps_can_have_special_access_to_accelerators)) { + return UNSUPPORTED_ON_DEVICE; + } + + return super.getAvailabilityStatus(); + } + + @Override + protected CharSequence getSummaryOn() { + return resText(R.string.Google_apps_special_accelerator_access_summary_granted); + } + + @Override + protected CharSequence getSummaryOff() { + return resText(R.string.Google_apps_special_accelerator_access_summary_not_granted); + } +} From 4e37451784815caae19da021683548dec7612c1c Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Wed, 3 May 2023 08:57:01 +0300 Subject: [PATCH 032/162] add GNSS PSDS setting --- res/values/strings_ext.xml | 10 ++++ res/xml/location_settings.xml | 5 ++ .../location/GnssPsdsPrefController.java | 49 +++++++++++++++++++ 3 files changed, 64 insertions(+) create mode 100644 src/com/android/settings/location/GnssPsdsPrefController.java diff --git a/res/values/strings_ext.xml b/res/values/strings_ext.xml index a7d5ff6d9f9..cbe556d6b7d 100644 --- a/res/values/strings_ext.xml +++ b/res/values/strings_ext.xml @@ -74,4 +74,14 @@ Examples of such apps: This setting applies to all users on the device." + Predicted Satellite Data Service (PSDS) + +"If PSDS is turned on, static PSDS information files will be downloaded periodically to improve location resolution speed and accuracy. +No query or data is sent to the server. These files contain orbits and statuses of satellites, Earth environmental data and time adjustment information." + + GrapheneOS server + Standard server + Off + Will make acquiring location lock significantly slower, especially if SUPL is turned off too + diff --git a/res/xml/location_settings.xml b/res/xml/location_settings.xml index c22c22c09a9..c115ccf6486 100644 --- a/res/xml/location_settings.xml +++ b/res/xml/location_settings.xml @@ -82,6 +82,11 @@ android:title="@string/pref_gnss_supl_title" settings:controller="com.android.settings.location.GnssSuplPrefController"/> + + Date: Wed, 24 May 2023 13:32:14 +0300 Subject: [PATCH 033/162] add connectivity checks setting --- res/values/strings_ext.xml | 10 +++++++ res/xml/network_provider_internet.xml | 6 ++++ .../ConnectivityChecksPrefController.java | 29 +++++++++++++++++++ 3 files changed, 45 insertions(+) create mode 100644 src/com/android/settings/network/ConnectivityChecksPrefController.java diff --git a/res/values/strings_ext.xml b/res/values/strings_ext.xml index cbe556d6b7d..73019e6f41e 100644 --- a/res/values/strings_ext.xml +++ b/res/values/strings_ext.xml @@ -84,4 +84,14 @@ No query or data is sent to the server. These files contain orbits and statuses Off Will make acquiring location lock significantly slower, especially if SUPL is turned off too + GrapheneOS server + Standard (Google) server + Off + + Internet connectivity checks + +"Connectivity check is a special empty server request that is made to find out whether the current network has internet connection. +There are HTTP, HTTPS, DNS, DNS-over-TLS and DNS-over-HTTPS connectivity checks. + + diff --git a/res/xml/network_provider_internet.xml b/res/xml/network_provider_internet.xml index d04f6999b1c..b4becf7c709 100644 --- a/res/xml/network_provider_internet.xml +++ b/res/xml/network_provider_internet.xml @@ -127,6 +127,12 @@ android:order="30" settings:controller="com.android.settings.network.CellularSecurityPreferenceController"/> + + Date: Wed, 24 May 2023 14:57:01 +0300 Subject: [PATCH 034/162] add common resources for auto-off settings --- res/values/strings_ext.xml | 1 + .../android/settings/ext/AutoOffSetting.java | 25 +++++++++++++++++++ 2 files changed, 26 insertions(+) create mode 100644 src/com/android/settings/ext/AutoOffSetting.java diff --git a/res/values/strings_ext.xml b/res/values/strings_ext.xml index 73019e6f41e..dc5f42758b2 100644 --- a/res/values/strings_ext.xml +++ b/res/values/strings_ext.xml @@ -1,6 +1,7 @@ Hardware SKU + Never Enable Enabled diff --git a/src/com/android/settings/ext/AutoOffSetting.java b/src/com/android/settings/ext/AutoOffSetting.java new file mode 100644 index 00000000000..98be94b8589 --- /dev/null +++ b/src/com/android/settings/ext/AutoOffSetting.java @@ -0,0 +1,25 @@ +package com.android.settings.ext; + +import com.android.settings.R; + +import static java.util.concurrent.TimeUnit.HOURS; +import static java.util.concurrent.TimeUnit.MINUTES; +import static java.util.concurrent.TimeUnit.SECONDS; + +public class AutoOffSetting { + + public static void getEntries(AbstractListPreferenceController.Entries entries) { + entries.add(R.string.auto_off_never, 0); + entries.add(15, SECONDS); + entries.add(30, SECONDS); + entries.add(1, MINUTES); + entries.add(2, MINUTES); + entries.add(5, MINUTES); + entries.add(10, MINUTES); + entries.add(30, MINUTES); + entries.add(1, HOURS); + entries.add(2, HOURS); + entries.add(4, HOURS); + entries.add(8, HOURS); + } +} From d510fe61e75d64d56a1628724fe18a423ec73d28 Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Thu, 25 May 2023 16:25:33 +0300 Subject: [PATCH 035/162] add Wi-Fi auto-off setting --- res/values/strings_ext.xml | 2 + res/xml/exploit_protection_settings.xml | 5 +++ .../wifi/WifiAutoOffPrefController.java | 39 +++++++++++++++++++ 3 files changed, 46 insertions(+) create mode 100644 src/com/android/settings/wifi/WifiAutoOffPrefController.java diff --git a/res/values/strings_ext.xml b/res/values/strings_ext.xml index dc5f42758b2..770ec6e7ddb 100644 --- a/res/values/strings_ext.xml +++ b/res/values/strings_ext.xml @@ -95,4 +95,6 @@ No query or data is sent to the server. These files contain orbits and statuses There are HTTP, HTTPS, DNS, DNS-over-TLS and DNS-over-HTTPS connectivity checks. + Turn off Wi-Fi automatically + If Wi-Fi is disconnected, it will be turned off after the selected timeout. diff --git a/res/xml/exploit_protection_settings.xml b/res/xml/exploit_protection_settings.xml index faaf3b59180..b5f3a0e1dde 100644 --- a/res/xml/exploit_protection_settings.xml +++ b/res/xml/exploit_protection_settings.xml @@ -10,6 +10,11 @@ android:title="@string/auto_reboot_title" settings:controller="com.android.settings.security.AutoRebootPrefController" /> + + diff --git a/src/com/android/settings/wifi/WifiAutoOffPrefController.java b/src/com/android/settings/wifi/WifiAutoOffPrefController.java new file mode 100644 index 00000000000..b8ec16bd69a --- /dev/null +++ b/src/com/android/settings/wifi/WifiAutoOffPrefController.java @@ -0,0 +1,39 @@ +package com.android.settings.wifi; + +import android.content.Context; +import android.content.pm.PackageManager; +import android.ext.settings.ExtSettings; + +import androidx.preference.PreferenceScreen; + +import com.android.settings.R; +import com.android.settings.ext.AutoOffSetting; +import com.android.settings.ext.IntSettingPrefController; +import com.android.settings.ext.RadioButtonPickerFragment2; + +public class WifiAutoOffPrefController extends IntSettingPrefController { + + public WifiAutoOffPrefController(Context ctx, String key) { + super(ctx, key, ExtSettings.WIFI_AUTO_OFF); + } + + @Override + public int getAvailabilityStatus() { + int r = super.getAvailabilityStatus(); + if (r == AVAILABLE) { + return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI) ? + AVAILABLE : UNSUPPORTED_ON_DEVICE; + } + return r; + } + + @Override + public void addPrefsBeforeList(RadioButtonPickerFragment2 fragment, PreferenceScreen screen) { + addFooterPreference(screen, R.string.wifi_auto_off_footer); + } + + @Override + protected void getEntries(Entries entries) { + AutoOffSetting.getEntries(entries); + } +} From 28b2d90da8836ab8b310c35f8012b95e7a2871aa Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Wed, 24 May 2023 15:01:04 +0300 Subject: [PATCH 036/162] add Bluetooth auto-off setting --- res/values/strings_ext.xml | 6 +++ res/xml/exploit_protection_settings.xml | 5 +++ .../BluetoothAutoOffPrefController.java | 39 +++++++++++++++++++ 3 files changed, 50 insertions(+) create mode 100644 src/com/android/settings/bluetooth/BluetoothAutoOffPrefController.java diff --git a/res/values/strings_ext.xml b/res/values/strings_ext.xml index 770ec6e7ddb..44ce80d094d 100644 --- a/res/values/strings_ext.xml +++ b/res/values/strings_ext.xml @@ -97,4 +97,10 @@ There are HTTP, HTTPS, DNS, DNS-over-TLS and DNS-over-HTTPS connectivity checks. Turn off Wi-Fi automatically If Wi-Fi is disconnected, it will be turned off after the selected timeout. + + Turn off Bluetooth automatically + +"If there are no connected devices, Bluetooth will turn off after the selected timeout." + + diff --git a/res/xml/exploit_protection_settings.xml b/res/xml/exploit_protection_settings.xml index b5f3a0e1dde..bfd7e4dc3d9 100644 --- a/res/xml/exploit_protection_settings.xml +++ b/res/xml/exploit_protection_settings.xml @@ -15,6 +15,11 @@ android:title="@string/wifi_auto_off_title" settings:controller="com.android.settings.wifi.WifiAutoOffPrefController"/> + + diff --git a/src/com/android/settings/bluetooth/BluetoothAutoOffPrefController.java b/src/com/android/settings/bluetooth/BluetoothAutoOffPrefController.java new file mode 100644 index 00000000000..14791951802 --- /dev/null +++ b/src/com/android/settings/bluetooth/BluetoothAutoOffPrefController.java @@ -0,0 +1,39 @@ +package com.android.settings.bluetooth; + +import android.content.Context; +import android.content.pm.PackageManager; +import android.ext.settings.ExtSettings; + +import androidx.preference.PreferenceScreen; + +import com.android.settings.R; +import com.android.settings.ext.AutoOffSetting; +import com.android.settings.ext.IntSettingPrefController; +import com.android.settings.ext.RadioButtonPickerFragment2; + +public class BluetoothAutoOffPrefController extends IntSettingPrefController { + + public BluetoothAutoOffPrefController(Context ctx, String key) { + super(ctx, key, ExtSettings.BLUETOOTH_AUTO_OFF); + } + + @Override + public int getAvailabilityStatus() { + int r = super.getAvailabilityStatus(); + if (r == AVAILABLE) { + return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH) ? + AVAILABLE : UNSUPPORTED_ON_DEVICE; + } + return r; + } + + @Override + public void addPrefsBeforeList(RadioButtonPickerFragment2 fragment, PreferenceScreen screen) { + addFooterPreference(screen, R.string.bluetooth_auto_off_footer); + } + + @Override + protected void getEntries(Entries entries) { + AutoOffSetting.getEntries(entries); + } +} From d57a3732f30b0d8af6ba529e812a1c4fd34d21bc Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Thu, 25 May 2023 16:47:42 +0300 Subject: [PATCH 037/162] add exec spawning setting --- res/values/strings_ext.xml | 4 +++ res/xml/exploit_protection_settings.xml | 6 +++- .../security/ExecSpawningFragment.java | 34 +++++++++++++++++++ .../security/ExecSpawningPrefController.java | 13 +++++++ 4 files changed, 56 insertions(+), 1 deletion(-) create mode 100644 src/com/android/settings/security/ExecSpawningFragment.java create mode 100644 src/com/android/settings/security/ExecSpawningPrefController.java diff --git a/res/values/strings_ext.xml b/res/values/strings_ext.xml index 44ce80d094d..37b4eb73129 100644 --- a/res/values/strings_ext.xml +++ b/res/values/strings_ext.xml @@ -103,4 +103,8 @@ There are HTTP, HTTPS, DNS, DNS-over-TLS and DNS-over-HTTPS connectivity checks. "If there are no connected devices, Bluetooth will turn off after the selected timeout." + Secure app spawning + Use secure app spawning + Launch apps in a more secure way than Android which takes slightly longer and increases memory usage by app processes. + diff --git a/res/xml/exploit_protection_settings.xml b/res/xml/exploit_protection_settings.xml index bfd7e4dc3d9..ada50481305 100644 --- a/res/xml/exploit_protection_settings.xml +++ b/res/xml/exploit_protection_settings.xml @@ -24,7 +24,11 @@ android:key="app_exploit_protection_settings" android:title="@string/app_exploit_protection_category"> - + diff --git a/src/com/android/settings/security/ExecSpawningFragment.java b/src/com/android/settings/security/ExecSpawningFragment.java new file mode 100644 index 00000000000..1ab1f744617 --- /dev/null +++ b/src/com/android/settings/security/ExecSpawningFragment.java @@ -0,0 +1,34 @@ +package com.android.settings.security; + +import android.ext.settings.BoolSetting; +import android.ext.settings.ExtSettings; +import android.net.Uri; + +import com.android.settings.R; +import com.android.settings.ext.BoolSettingFragment; +import com.android.settingslib.widget.FooterPreference; + +public class ExecSpawningFragment extends BoolSettingFragment { + + @Override + protected BoolSetting getSetting() { + return ExtSettings.EXEC_SPAWNING; + } + + @Override + protected CharSequence getTitle() { + return getText(R.string.exec_spawning_title); + } + + @Override + protected CharSequence getMainSwitchTitle() { + return getText(R.string.exec_spawning_title_inner); + } + + @Override + protected FooterPreference makeFooterPref(FooterPreference.Builder builder) { + FooterPreference p = builder.setTitle(R.string.exec_spawning_footer).build(); + setFooterPrefLearnMoreUri(p, Uri.parse("https://grapheneos.org/usage#exec-spawning")); + return p; + } +} diff --git a/src/com/android/settings/security/ExecSpawningPrefController.java b/src/com/android/settings/security/ExecSpawningPrefController.java new file mode 100644 index 00000000000..cd2be5cfc71 --- /dev/null +++ b/src/com/android/settings/security/ExecSpawningPrefController.java @@ -0,0 +1,13 @@ +package com.android.settings.security; + +import android.content.Context; +import android.ext.settings.ExtSettings; + +import com.android.settings.ext.BoolSettingFragmentPrefController; + +public class ExecSpawningPrefController extends BoolSettingFragmentPrefController { + + public ExecSpawningPrefController(Context ctx, String key) { + super(ctx, key, ExtSettings.EXEC_SPAWNING); + } +} From b198d3c05df1f7fadbdc9e6530d61a239b432081 Mon Sep 17 00:00:00 2001 From: flawedworld Date: Sun, 25 Jun 2023 13:53:58 +0100 Subject: [PATCH 038/162] Mark all DSU options as unsupported --- src/com/android/settings/development/DSULoader.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/com/android/settings/development/DSULoader.java b/src/com/android/settings/development/DSULoader.java index fede67a7766..957e3d79e6f 100644 --- a/src/com/android/settings/development/DSULoader.java +++ b/src/com/android/settings/development/DSULoader.java @@ -305,7 +305,7 @@ Date getDeviceSPL() { } boolean isSupported() { - boolean supported = true; + boolean supported = false; String cpu = getDeviceCpu(); if (!mCpuAbi.equals(cpu)) { Slog.i(TAG, mCpuAbi + " != " + cpu); From 90aead8c50d85dcbc77844b27dbf1eb54509eca1 Mon Sep 17 00:00:00 2001 From: quh4gko8 <88831734+quh4gko8@users.noreply.github.com> Date: Sat, 1 Jul 2023 07:07:57 +0000 Subject: [PATCH 039/162] Remove "Add users from lock screen" setting --- .../users/AddUserWhenLockedPreferenceController.java | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/src/com/android/settings/users/AddUserWhenLockedPreferenceController.java b/src/com/android/settings/users/AddUserWhenLockedPreferenceController.java index 38aef0f217b..7618f73e4b0 100644 --- a/src/com/android/settings/users/AddUserWhenLockedPreferenceController.java +++ b/src/com/android/settings/users/AddUserWhenLockedPreferenceController.java @@ -51,17 +51,7 @@ public void updateState(Preference preference) { @Override public int getAvailabilityStatus() { - if (mContext.getResources() - .getBoolean( - com.android.internal.R.bool.config_userSwitchingMustGoThroughLoginScreen)) { - return UNSUPPORTED_ON_DEVICE; - } else if (!mUserCaps.isAdmin()) { - return DISABLED_FOR_USER; - } else if (mUserCaps.mDisallowAddUser && !mUserCaps.mDisallowAddUserSetByAdmin) { - return DISABLED_FOR_USER; - } else { - return AVAILABLE; - } + return UNSUPPORTED_ON_DEVICE; } @Override From 59dd7c1cc6ed148ed015db23248c4a85d8302691 Mon Sep 17 00:00:00 2001 From: quh4gko8 <88831734+quh4gko8@users.noreply.github.com> Date: Sun, 23 Jul 2023 19:53:04 +0000 Subject: [PATCH 040/162] Factor out common code for reading/writing UserManager restrictions --- .../settings/users/UserDetailsSettings.java | 2 + .../settings/users/UserRestrictions.java | 66 +++++++++++++++++++ 2 files changed, 68 insertions(+) create mode 100644 src/com/android/settings/users/UserRestrictions.java diff --git a/src/com/android/settings/users/UserDetailsSettings.java b/src/com/android/settings/users/UserDetailsSettings.java index 14fb6f353d0..e085b6fb793 100644 --- a/src/com/android/settings/users/UserDetailsSettings.java +++ b/src/com/android/settings/users/UserDetailsSettings.java @@ -118,6 +118,7 @@ public class UserDetailsSettings extends SettingsPreferenceFragment @VisibleForTesting /** The user being studied (not the user doing the studying). */ UserInfo mUserInfo; + private UserRestrictions userRestrictions; @Override public int getMetricsCategory() { @@ -365,6 +366,7 @@ void initialize(Context context, Bundle arguments) { boolean isNewUser = arguments.getBoolean(AppRestrictionsFragment.EXTRA_NEW_USER, false); mUserInfo = mUserManager.getUserInfo(userId); + userRestrictions = UserRestrictions.createInstance(mUserManager, mUserInfo); mSwitchUserPref = findPreference(KEY_SWITCH_USER); mPhonePref = findPreference(KEY_ENABLE_TELEPHONY_CALLING); diff --git a/src/com/android/settings/users/UserRestrictions.java b/src/com/android/settings/users/UserRestrictions.java new file mode 100644 index 00000000000..6ab1b301118 --- /dev/null +++ b/src/com/android/settings/users/UserRestrictions.java @@ -0,0 +1,66 @@ +package com.android.settings.users; + +import android.content.Context; +import android.content.pm.UserInfo; +import android.os.Bundle; +import android.os.UserManager; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +public final class UserRestrictions { + + @NonNull + private final UserManager userManager; + @NonNull + public final UserInfo userInfo; + + @Nullable + public static UserRestrictions createInstance(@NonNull Context ctx, int userId) { + UserManager userManager = ctx.getSystemService(UserManager.class); + if (userManager == null) { + return null; + } + + return createInstance(userManager, userId); + } + + @Nullable + public static UserRestrictions createInstance(@NonNull UserManager userManager, int userId) { + UserInfo userInfo = userManager.getUserInfo(userId); + if (userInfo == null) { + return null; + } + + return new UserRestrictions(userManager, userInfo); + } + + @NonNull + public static UserRestrictions createInstance(@NonNull UserManager userManager, @NonNull UserInfo userInfo) { + return new UserRestrictions(userManager, userInfo); + } + + private UserRestrictions(@NonNull UserManager userManager, @NonNull UserInfo userInfo) { + this.userManager = userManager; + this.userInfo = userInfo; + } + + public boolean isSet(String restrictionKey) { + final boolean isSetFromUser = userManager.hasUserRestriction(restrictionKey, userInfo.getUserHandle()); + if (userInfo.isGuest()) { + return isSetFromUser || userManager.getDefaultGuestRestrictions().getBoolean(restrictionKey); + } + + return isSetFromUser; + } + + public void set(String restrictionKey, boolean enableRestriction) { + if (userInfo.isGuest()) { + Bundle defaultGuestRestrictions = userManager.getDefaultGuestRestrictions(); + defaultGuestRestrictions.putBoolean(restrictionKey, enableRestriction); + userManager.setDefaultGuestRestrictions(defaultGuestRestrictions); + } else { + userManager.setUserRestriction(restrictionKey, enableRestriction, userInfo.getUserHandle()); + } + } +} From 6e9fe6c758d0345887d60898699ccaf9cf7e1061 Mon Sep 17 00:00:00 2001 From: Pratyush Date: Sat, 3 Sep 2022 15:52:37 +0530 Subject: [PATCH 041/162] UserManager enable "install available apps" allowing adding (installed) apps from (owner) user manager ui. --- src/com/android/settings/users/UserDetailsSettings.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/com/android/settings/users/UserDetailsSettings.java b/src/com/android/settings/users/UserDetailsSettings.java index e085b6fb793..42594c2f7d4 100644 --- a/src/com/android/settings/users/UserDetailsSettings.java +++ b/src/com/android/settings/users/UserDetailsSettings.java @@ -91,7 +91,7 @@ public class UserDetailsSettings extends SettingsPreferenceFragment private static final int DIALOG_CONFIRM_GRANT_ADMIN = 7; /** Whether to enable the app_copying fragment. */ - private static final boolean SHOW_APP_COPYING_PREF = false; + private static final boolean SHOW_APP_COPYING_PREF = true; private static final int MESSAGE_PADDING = 20; @VisibleForTesting static final int REQUEST_CONFIRM_REMOVE = 1; @@ -458,7 +458,6 @@ void initialize(Context context, Bundle arguments) { } else { mPhonePref.setChecked(!mUserManager.hasUserRestriction( UserManager.DISALLOW_OUTGOING_CALLS, new UserHandle(userId))); - removePreference(KEY_APP_COPYING); } // Remove preference KEY_REMOVE_USER if DISALLOW_REMOVE_USER restriction is set From 5d3b9132d9e175003441b2eedf84d3f96ecf1016 Mon Sep 17 00:00:00 2001 From: quh4gko8 <88831734+quh4gko8@users.noreply.github.com> Date: Thu, 20 Jul 2023 05:07:49 +0000 Subject: [PATCH 042/162] UserManager settings for apps installs and updates --- res/values/strings_ext.xml | 11 ++ res/xml/user_details_settings.xml | 4 + .../users/UserAppsInstallSettings.java | 177 ++++++++++++++++++ .../settings/users/UserDetailsSettings.java | 11 ++ 4 files changed, 203 insertions(+) create mode 100644 src/com/android/settings/users/UserAppsInstallSettings.java diff --git a/res/values/strings_ext.xml b/res/values/strings_ext.xml index 37b4eb73129..a01ad75d9ed 100644 --- a/res/values/strings_ext.xml +++ b/res/values/strings_ext.xml @@ -107,4 +107,15 @@ There are HTTP, HTTPS, DNS, DNS-over-TLS and DNS-over-HTTPS connectivity checks. Use secure app spawning Launch apps in a more secure way than Android which takes slightly longer and increases memory usage by app processes. + + App installs and updates + + Enabled + Enabled for first party sources + Disabled + + Enable app installs and updates + Enable app installs and updates from first party sources only + Disable app installs and updates + diff --git a/res/xml/user_details_settings.xml b/res/xml/user_details_settings.xml index 8e15d14bf5a..2cd01c1ef7d 100644 --- a/res/xml/user_details_settings.xml +++ b/res/xml/user_details_settings.xml @@ -33,6 +33,10 @@ android:key="app_and_content_access" android:icon="@drawable/ic_lock_closed" android:title="@string/user_restrictions_title" /> + getCandidates() { + Context ctx = requireContext(); + ArrayList candidates = new ArrayList<>(3); + if (!userRestrictions.userInfo.isGuest()) { + candidates.add(new CandidateInfoExtra(ctx.getString(R.string.user_app_install_enabled), + ctx.getString(R.string.user_app_install_enabled_desc), + INSTALL_ENABLED, true)); + } + candidates.add(new CandidateInfoExtra(ctx.getString(R.string.user_app_install_enabled_first_party_sources), + ctx.getString(R.string.user_app_install_enabled_first_party_sources_desc), + INSTALL_FIRST_PARTY_ENABLED, true)); + candidates.add(new CandidateInfoExtra(ctx.getString(R.string.user_app_install_disabled), + ctx.getString(R.string.user_app_install_disabled_desc), + INSTALL_DISABLED, true)); + return candidates; + } + + @Override + public void bindPreferenceExtra(SelectorWithWidgetPreference pref, String key, CandidateInfo info, + String defaultKey, String systemDefaultKey) { + pref.setSingleLineTitle(false); + + if (info instanceof CandidateInfoExtra) { + var cie = (CandidateInfoExtra) info; + pref.setSummary(cie.loadSummary()); + } + } + + @Override + protected String getDefaultKey() { + return getCurrentInstallRestriction(userRestrictions); + } + + @Override + protected boolean setDefaultKey(String key) { + if (key == null) { + return false; + } + + switch (key) { + case INSTALL_ENABLED: + if (userRestrictions.userInfo.isGuest()) { + return false; + } + userRestrictions.set(UserManager.DISALLOW_INSTALL_APPS, false); + userRestrictions.set(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES, false); + return true; + case INSTALL_FIRST_PARTY_ENABLED: + userRestrictions.set(UserManager.DISALLOW_INSTALL_APPS, false); + if (!userRestrictions.userInfo.isGuest()) { + userRestrictions.set(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES, true); + } + return true; + case INSTALL_DISABLED: + userRestrictions.set(UserManager.DISALLOW_INSTALL_APPS, true); + if (!userRestrictions.userInfo.isGuest()) { + userRestrictions.set(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES, true); + } + return true; + default: + return false; + } + } + + @Override + public int getMetricsCategory() { + return METRICS_CATEGORY_UNKNOWN; + } + + @Override + public void onResume() { + super.onResume(); + updateCandidates(); + } +} diff --git a/src/com/android/settings/users/UserDetailsSettings.java b/src/com/android/settings/users/UserDetailsSettings.java index 42594c2f7d4..7555279f01c 100644 --- a/src/com/android/settings/users/UserDetailsSettings.java +++ b/src/com/android/settings/users/UserDetailsSettings.java @@ -79,6 +79,8 @@ public class UserDetailsSettings extends SettingsPreferenceFragment private static final String KEY_APP_AND_CONTENT_ACCESS = "app_and_content_access"; private static final String KEY_APP_COPYING = "app_copying"; + private static final String KEY_APP_INSTALLS = "app_installs"; + /** Integer extra containing the userId to manage */ static final String EXTRA_USER_ID = "user_id"; @@ -114,6 +116,7 @@ public class UserDetailsSettings extends SettingsPreferenceFragment Preference mRemoveUserPref; @VisibleForTesting TwoStatePreference mGrantAdminPref; + Preference mAppsInstallsPref; @VisibleForTesting /** The user being studied (not the user doing the studying). */ @@ -150,6 +153,8 @@ public void onResume() { if (mUserInfo.isGuest() && mGuestUserAutoCreated) { mRemoveUserPref.setEnabled((mUserInfo.flags & UserInfo.FLAG_INITIALIZED) != 0); } + mAppsInstallsPref.setSummary(UserAppsInstallSettings.getDescription( + requireContext(), userRestrictions)); } @Override @@ -190,6 +195,9 @@ public boolean onPreferenceClick(Preference preference) { } else if (preference == mAppCopyingPref) { openAppCopyingScreen(); return true; + } else if (preference == mAppsInstallsPref) { + UserAppsInstallSettings.launch(preference, mUserInfo.id); + return true; } return false; } @@ -376,6 +384,7 @@ void initialize(Context context, Bundle arguments) { mGrantAdminPref = findPreference(KEY_GRANT_ADMIN); mGrantAdminPref.setChecked(mUserInfo.isAdmin()); + mAppsInstallsPref = findPreference(KEY_APP_INSTALLS); mSwitchUserPref.setVisible(mUserCaps.mUserSwitchingUiEnabled && UserHandle.myUserId() != mUserInfo.id); @@ -432,6 +441,7 @@ void initialize(Context context, Bundle arguments) { removePreference(KEY_ENABLE_TELEPHONY_CALLING); removePreference(KEY_APP_AND_CONTENT_ACCESS); removePreference(KEY_APP_COPYING); + removePreference(KEY_APP_INSTALLS); } else { if (!Utils.isVoiceCapable(context)) { // no telephony removePreference(KEY_ENABLE_TELEPHONY_CALLING); @@ -466,6 +476,7 @@ void initialize(Context context, Bundle arguments) { removePreference(KEY_REMOVE_USER); } + mAppsInstallsPref.setOnPreferenceClickListener(this); mPhonePref.setOnPreferenceChangeListener(this); mGrantAdminPref.setOnPreferenceChangeListener(this); mAppAndContentAccessPref.setOnPreferenceClickListener(this); From 12cfaa0e41cf89e18f988fae5d9b9b3644be02ef Mon Sep 17 00:00:00 2001 From: quh4gko8 <88831734+quh4gko8@users.noreply.github.com> Date: Tue, 13 Jun 2023 12:19:41 +0000 Subject: [PATCH 043/162] UserManager settings for running in background --- res/values/strings_ext.xml | 2 ++ res/xml/user_details_settings.xml | 4 ++++ .../android/settings/users/UserDetailsSettings.java | 13 +++++++++++++ 3 files changed, 19 insertions(+) diff --git a/res/values/strings_ext.xml b/res/values/strings_ext.xml index a01ad75d9ed..79c2ccd45d6 100644 --- a/res/values/strings_ext.xml +++ b/res/values/strings_ext.xml @@ -117,5 +117,7 @@ There are HTTP, HTTPS, DNS, DNS-over-TLS and DNS-over-HTTPS connectivity checks. Enable app installs and updates Enable app installs and updates from first party sources only Disable app installs and updates + + Allow running in background diff --git a/res/xml/user_details_settings.xml b/res/xml/user_details_settings.xml index 2cd01c1ef7d..5f6df097ec9 100644 --- a/res/xml/user_details_settings.xml +++ b/res/xml/user_details_settings.xml @@ -25,6 +25,10 @@ android:key="user_grant_admin" android:icon="@drawable/ic_admin_panel_settings" android:title="@string/user_grant_admin" /> + Date: Wed, 26 Jul 2023 09:45:29 +0000 Subject: [PATCH 044/162] Disable app copying preference when the user has DISALLOW_INSTALL_APPS restriction --- src/com/android/settings/users/UserDetailsSettings.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/com/android/settings/users/UserDetailsSettings.java b/src/com/android/settings/users/UserDetailsSettings.java index f9cad65daeb..c3484111183 100644 --- a/src/com/android/settings/users/UserDetailsSettings.java +++ b/src/com/android/settings/users/UserDetailsSettings.java @@ -158,6 +158,7 @@ public void onResume() { } mAppsInstallsPref.setSummary(UserAppsInstallSettings.getDescription( requireContext(), userRestrictions)); + mAppCopyingPref.setEnabled(!userRestrictions.isSet(UserManager.DISALLOW_INSTALL_APPS)); } @Override From e893e7f9fc0e20f74d936b347072df623a341c51 Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Sat, 2 Mar 2024 11:24:34 +0200 Subject: [PATCH 045/162] add support for disabling non-system apps --- .../settings/spa/app/appinfo/AppDisableButton.kt | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/com/android/settings/spa/app/appinfo/AppDisableButton.kt b/src/com/android/settings/spa/app/appinfo/AppDisableButton.kt index 555e9f14c61..07d583cde30 100644 --- a/src/com/android/settings/spa/app/appinfo/AppDisableButton.kt +++ b/src/com/android/settings/spa/app/appinfo/AppDisableButton.kt @@ -31,6 +31,7 @@ import com.android.settingslib.spa.widget.dialog.AlertDialogButton import com.android.settingslib.spa.widget.dialog.rememberAlertDialogPresenter import com.android.settingslib.spaprivileged.framework.common.devicePolicyManager import com.android.settingslib.spaprivileged.framework.common.userManager +import com.android.settingslib.spaprivileged.model.app.installed import com.android.settingslib.spaprivileged.model.app.isDisabledUntilUsed import com.android.settingslib.Utils as SettingsLibUtils @@ -47,7 +48,7 @@ class AppDisableButton( @Composable fun getActionButton(app: ApplicationInfo): ActionButton? { - if (!app.isSystemApp) return null + if (!app.installed) return null return when { app.enabled && !app.isDisabledUntilUsed -> { @@ -62,6 +63,8 @@ class AppDisableButton( * Gets whether a package can be disabled. */ private fun ApplicationInfo.canBeDisabled(): Boolean = when { + !isSystemApp -> appButtonRepository.isAllowUninstallOrArchive(context, this) + // Try to prevent the user from bricking their phone by not allowing disabling of apps // signed with the system certificate. isSignedWithPlatformKey -> false @@ -98,7 +101,12 @@ class AppDisableButton( // Currently we apply the same device policy for both the uninstallation and disable // button. if (!appButtonRepository.isUninstallBlockedByAdmin(app)) { - dialogPresenter.open() + if (app.isSystemApp) { + dialogPresenter.open() + } else { + packageInfoPresenter.disable() + } + } } } From 0cb09d32eb51c18e53d7e73a9edaa5464c004ac3 Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Sat, 2 Mar 2024 12:29:45 +0200 Subject: [PATCH 046/162] don't show "More options" button in App info uninstall dialog That button opens app's App info screen. --- src/com/android/settings/spa/app/AppUtil.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/com/android/settings/spa/app/AppUtil.kt b/src/com/android/settings/spa/app/AppUtil.kt index 64da61380f5..7b319aeddeb 100644 --- a/src/com/android/settings/spa/app/AppUtil.kt +++ b/src/com/android/settings/spa/app/AppUtil.kt @@ -37,6 +37,7 @@ fun Context.startUninstallActivity( val intent = Intent(Intent.ACTION_UNINSTALL_PACKAGE, packageUri).apply { putExtra(Intent.EXTRA_UNINSTALL_ALL_USERS, forAllUsers) + putExtra(Intent.EXTRA_UNINSTALL_SHOW_MORE_OPTIONS_BUTTON, false) } startActivityAsUser(intent, userHandle) -} \ No newline at end of file +} From c2e1378babb0f4ea1718d73d2a1854cb18839756 Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Sat, 2 Mar 2024 11:19:46 +0200 Subject: [PATCH 047/162] add Storage Scopes link to the "App info" screen --- res/values/strings_ext.xml | 3 +- .../spa/app/appinfo/AppInfoSettings.kt | 1 + .../app/appinfo/AppStorageScopesPreference.kt | 32 +++++++++++++++++++ 3 files changed, 35 insertions(+), 1 deletion(-) create mode 100644 src/com/android/settings/spa/app/appinfo/AppStorageScopesPreference.kt diff --git a/res/values/strings_ext.xml b/res/values/strings_ext.xml index 79c2ccd45d6..cf015c0d004 100644 --- a/res/values/strings_ext.xml +++ b/res/values/strings_ext.xml @@ -85,6 +85,8 @@ No query or data is sent to the server. These files contain orbits and statuses Off Will make acquiring location lock significantly slower, especially if SUPL is turned off too + Storage Scopes + GrapheneOS server Standard (Google) server Off @@ -119,5 +121,4 @@ There are HTTP, HTTPS, DNS, DNS-over-TLS and DNS-over-HTTPS connectivity checks. Disable app installs and updates Allow running in background - diff --git a/src/com/android/settings/spa/app/appinfo/AppInfoSettings.kt b/src/com/android/settings/spa/app/appinfo/AppInfoSettings.kt index 2004757ed03..4e6796d4ced 100644 --- a/src/com/android/settings/spa/app/appinfo/AppInfoSettings.kt +++ b/src/com/android/settings/spa/app/appinfo/AppInfoSettings.kt @@ -149,6 +149,7 @@ private fun AppInfoSettings(packageInfoPresenter: PackageInfoPresenter) { AppPermissionPreference(app) ManageTargetAppFunctionAccessPreference(app) ManageAgentAppFunctionAccessPreference(app) + AppStorageScopesPreference(app) AppStoragePreference(app) InstantAppDomainsPreference(app) AppDataUsagePreference(app) diff --git a/src/com/android/settings/spa/app/appinfo/AppStorageScopesPreference.kt b/src/com/android/settings/spa/app/appinfo/AppStorageScopesPreference.kt new file mode 100644 index 00000000000..cbcd8944f56 --- /dev/null +++ b/src/com/android/settings/spa/app/appinfo/AppStorageScopesPreference.kt @@ -0,0 +1,32 @@ +package com.android.settings.spa.app.appinfo + +import android.app.StorageScope +import android.content.pm.ApplicationInfo +import android.content.pm.GosPackageState +import android.content.pm.GosPackageStateFlag +import androidx.compose.runtime.Composable +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.stringResource +import com.android.settings.R +import com.android.settingslib.spa.widget.preference.Preference +import com.android.settingslib.spa.widget.preference.PreferenceModel +import com.android.settingslib.spaprivileged.model.app.userHandle +import com.android.settingslib.spaprivileged.model.app.userId + +@Composable +fun AppStorageScopesPreference(app: ApplicationInfo) { + val pkgName = app.packageName + if (!GosPackageState.get(pkgName, app.userId).hasFlag(GosPackageStateFlag.STORAGE_SCOPES_ENABLED)) { + return + } + + val context = LocalContext.current + + Preference(object : PreferenceModel { + override val title = stringResource(R.string.storage_scopes) + override val onClick = { + val intent = StorageScope.createConfigActivityIntent(pkgName) + context.startActivityAsUser(intent, app.userHandle) + } + }) +} From 4b4c1636472903506df851e6628d4ac9f2588f1d Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Sat, 2 Mar 2024 11:20:31 +0200 Subject: [PATCH 048/162] add Storage Scopes link to "All files access" screen --- .../spa/app/specialaccess/AllFilesAccess.kt | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/com/android/settings/spa/app/specialaccess/AllFilesAccess.kt b/src/com/android/settings/spa/app/specialaccess/AllFilesAccess.kt index f6c08c0ca7c..6dba4817a2a 100644 --- a/src/com/android/settings/spa/app/specialaccess/AllFilesAccess.kt +++ b/src/com/android/settings/spa/app/specialaccess/AllFilesAccess.kt @@ -18,11 +18,19 @@ package com.android.settings.spa.app.specialaccess import android.Manifest import android.app.AppOpsManager +import android.app.StorageScope import android.app.settings.SettingsEnums import android.content.Context +import android.content.pm.PackageInfo +import androidx.compose.runtime.Composable +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.stringResource import com.android.settings.R import com.android.settings.overlay.FeatureFactory.Companion.featureFactory +import com.android.settingslib.spa.widget.preference.Preference +import com.android.settingslib.spa.widget.preference.PreferenceModel import com.android.settingslib.spaprivileged.model.app.AppOps +import com.android.settingslib.spaprivileged.model.app.userHandle import com.android.settingslib.spaprivileged.template.app.AppOpPermissionListModel import com.android.settingslib.spaprivileged.template.app.AppOpPermissionRecord import com.android.settingslib.spaprivileged.template.app.TogglePermissionAppListProvider @@ -54,4 +62,18 @@ class AllFilesAccessListModel(context: Context) : AppOpPermissionListModel(conte } featureFactory.metricsFeatureProvider.action(context, category, "") } + + @Composable + override fun extContent(record: AppOpPermissionRecord, pkgInfo: PackageInfo) { + val context = LocalContext.current + + Preference(object : PreferenceModel { + override val title = stringResource(R.string.storage_scopes) + override val onClick = { + val app = record.app + val i = StorageScope.createConfigActivityIntent(app.packageName) + context.startActivityAsUser(i, app.userHandle) + } + }) + } } From 1925ca8b46152b91953f3047707259c67eb91ad5 Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Fri, 8 Jul 2022 13:40:22 +0300 Subject: [PATCH 049/162] add OBB access toggle to "Install unknown apps" screen --- res/values/strings_ext.xml | 3 ++ .../app/specialaccess/InstallUnknownApps.kt | 52 ++++++++++++++++++- 2 files changed, 54 insertions(+), 1 deletion(-) diff --git a/res/values/strings_ext.xml b/res/values/strings_ext.xml index cf015c0d004..7afa35c78d4 100644 --- a/res/values/strings_ext.xml +++ b/res/values/strings_ext.xml @@ -121,4 +121,7 @@ There are HTTP, HTTPS, DNS, DNS-over-TLS and DNS-over-HTTPS connectivity checks. Disable app installs and updates Allow running in background + + Allow access to Android/obb folder + Required for installation of some large apps (mostly games) that use OBB expansion files diff --git a/src/com/android/settings/spa/app/specialaccess/InstallUnknownApps.kt b/src/com/android/settings/spa/app/specialaccess/InstallUnknownApps.kt index d6fe7160dbf..0a3d5219bc9 100644 --- a/src/com/android/settings/spa/app/specialaccess/InstallUnknownApps.kt +++ b/src/com/android/settings/spa/app/specialaccess/InstallUnknownApps.kt @@ -22,10 +22,18 @@ import android.app.AppOpsManager import android.app.AppOpsManager.MODE_DEFAULT import android.content.Context import android.content.pm.ApplicationInfo +import android.content.pm.GosPackageState +import android.content.pm.GosPackageStateFlag +import android.content.pm.PackageInfo import android.os.UserManager import androidx.compose.runtime.Composable +import androidx.compose.runtime.mutableStateOf +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.stringResource import com.android.settings.R import com.android.settingslib.spa.lifecycle.collectAsCallbackWithLifecycle +import com.android.settingslib.spa.widget.preference.SwitchPreference +import com.android.settingslib.spa.widget.preference.SwitchPreferenceModel import com.android.settingslib.spaprivileged.model.app.AppOps import com.android.settingslib.spaprivileged.model.app.AppOpsController import com.android.settingslib.spaprivileged.model.app.AppRecord @@ -44,7 +52,26 @@ object InstallUnknownAppsListProvider : TogglePermissionAppListProvider { data class InstallUnknownAppsRecord( override val app: ApplicationInfo, val appOpsController: AppOpsController, -) : AppRecord +) : AppRecord { + val isObbFlagSet = mutableStateOf(isObbFlagSet()) + + fun isObbFlagSet(): Boolean { + return GosPackageState.get(app.packageName, app.userId).hasFlag(GosPackageStateFlag.ALLOW_ACCESS_TO_OBB_DIRECTORY) + } + + fun setObbFlagState(state: Boolean): Boolean { + GosPackageState.edit(app.packageName, app.userId).run { + setFlagState(GosPackageStateFlag.ALLOW_ACCESS_TO_OBB_DIRECTORY, state) + killUidAfterApply() + if (apply()) { + isObbFlagSet.value = state + return true + } else { + return false + } + } + } +} class InstallUnknownAppsListModel(private val context: Context) : TogglePermissionAppListModel { @@ -84,6 +111,29 @@ class InstallUnknownAppsListModel(private val context: Context) : override fun setAllowed(record: InstallUnknownAppsRecord, newAllowed: Boolean) { record.appOpsController.setAllowed(newAllowed) + if (!newAllowed) { + record.setObbFlagState(false) + } + } + + @Composable + override fun extContent(record: InstallUnknownAppsRecord, pkgInfo: PackageInfo) { + val context = LocalContext.current + + SwitchPreference(object : SwitchPreferenceModel { + override val title = stringResource(R.string.allow_access_to_obb_directory_title) + override val summary = { + context.getString(R.string.allow_access_to_obb_directory_summary) + } + + override val checked = { + record.isObbFlagSet.value + } + override val onCheckedChange = { newChecked: Boolean -> + record.setObbFlagState(newChecked) + Unit + } + }) } companion object { From 8b14197a99f83a7ff4d025ec73f7c94f6c4a8f0e Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Sat, 2 Mar 2024 11:22:22 +0200 Subject: [PATCH 050/162] add Contact Scopes link to the "App info" screen --- res/values/strings_ext.xml | 2 ++ .../app/appinfo/AppContactScopesPreference.kt | 32 +++++++++++++++++++ .../spa/app/appinfo/AppInfoSettings.kt | 1 + 3 files changed, 35 insertions(+) create mode 100644 src/com/android/settings/spa/app/appinfo/AppContactScopesPreference.kt diff --git a/res/values/strings_ext.xml b/res/values/strings_ext.xml index 7afa35c78d4..94a22b60f8a 100644 --- a/res/values/strings_ext.xml +++ b/res/values/strings_ext.xml @@ -85,6 +85,8 @@ No query or data is sent to the server. These files contain orbits and statuses Off Will make acquiring location lock significantly slower, especially if SUPL is turned off too + Contact Scopes + Storage Scopes GrapheneOS server diff --git a/src/com/android/settings/spa/app/appinfo/AppContactScopesPreference.kt b/src/com/android/settings/spa/app/appinfo/AppContactScopesPreference.kt new file mode 100644 index 00000000000..be4cf6fadbc --- /dev/null +++ b/src/com/android/settings/spa/app/appinfo/AppContactScopesPreference.kt @@ -0,0 +1,32 @@ +package com.android.settings.spa.app.appinfo + +import android.content.pm.ApplicationInfo +import android.content.pm.GosPackageState +import android.content.pm.GosPackageStateFlag +import android.ext.cscopes.ContactScopesApi +import androidx.compose.runtime.Composable +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.stringResource +import com.android.settings.R +import com.android.settingslib.spa.widget.preference.Preference +import com.android.settingslib.spa.widget.preference.PreferenceModel +import com.android.settingslib.spaprivileged.model.app.userHandle +import com.android.settingslib.spaprivileged.model.app.userId + +@Composable +fun AppContactScopesPreference(app: ApplicationInfo) { + val pkgName = app.packageName + if (!GosPackageState.get(pkgName, app.userId).hasFlag(GosPackageStateFlag.CONTACT_SCOPES_ENABLED)) { + return + } + + val context = LocalContext.current + + Preference(object : PreferenceModel { + override val title = stringResource(R.string.contact_scopes) + override val onClick = { + val intent = ContactScopesApi.createConfigActivityIntent(pkgName) + context.startActivityAsUser(intent, app.userHandle) + } + }) +} diff --git a/src/com/android/settings/spa/app/appinfo/AppInfoSettings.kt b/src/com/android/settings/spa/app/appinfo/AppInfoSettings.kt index 4e6796d4ced..391a21273d8 100644 --- a/src/com/android/settings/spa/app/appinfo/AppInfoSettings.kt +++ b/src/com/android/settings/spa/app/appinfo/AppInfoSettings.kt @@ -150,6 +150,7 @@ private fun AppInfoSettings(packageInfoPresenter: PackageInfoPresenter) { ManageTargetAppFunctionAccessPreference(app) ManageAgentAppFunctionAccessPreference(app) AppStorageScopesPreference(app) + AppContactScopesPreference(app) AppStoragePreference(app) InstantAppDomainsPreference(app) AppDataUsagePreference(app) From d0c9018b5de3bc9ad3690942b31e51a23e290260 Mon Sep 17 00:00:00 2001 From: empratyush Date: Mon, 20 Jun 2022 22:16:29 +0300 Subject: [PATCH 051/162] add Battery share toggle --- Android.bp | 1 + res/values/strings_ext.xml | 3 + res/xml/power_usage_summary.xml | 9 ++ .../BatterySharePreferenceController.java | 99 +++++++++++++++++++ 4 files changed, 112 insertions(+) create mode 100644 src/com/android/settings/display/BatterySharePreferenceController.java diff --git a/Android.bp b/Android.bp index 47244771a25..32cb853e568 100644 --- a/Android.bp +++ b/Android.bp @@ -100,6 +100,7 @@ android_library { // Settings dependencies "FingerprintManagerInteractor", "MediaDrmSettingsFlagsLib", + "ReverseWirelessCharging", "Settings-change-ids", "SettingsLib", "SettingsLibActivityEmbedding", diff --git a/res/values/strings_ext.xml b/res/values/strings_ext.xml index 94a22b60f8a..775f9cc184a 100644 --- a/res/values/strings_ext.xml +++ b/res/values/strings_ext.xml @@ -126,4 +126,7 @@ There are HTTP, HTTPS, DNS, DNS-over-TLS and DNS-over-HTTPS connectivity checks. Allow access to Android/obb folder Required for installation of some large apps (mostly games) that use OBB expansion files + + Charge other devices by placing them on the back of your phone + Battery share diff --git a/res/xml/power_usage_summary.xml b/res/xml/power_usage_summary.xml index 4890560e3f7..9b1ba7b83f4 100644 --- a/res/xml/power_usage_summary.xml +++ b/res/xml/power_usage_summary.xml @@ -77,6 +77,15 @@ settings:controller="com.android.settings.display.BatteryPercentagePreferenceController" /> + + + + update()); + } + }; + + + public BatterySharePreferenceController(Context context, String preferenceKey) { + super(context, preferenceKey); + mContext = context; + wirelessCharger = ReverseWirelessCharger.getInstance(); + } + + public boolean isPlugged(Context context) { + Intent intent = context.registerReceiver(null, + new IntentFilter(Intent.ACTION_BATTERY_CHANGED)); + int plugged = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1); + return plugged == BatteryManager.BATTERY_PLUGGED_WIRELESS; + } + + @Override + public void displayPreference(PreferenceScreen screen) { + super.displayPreference(screen); + mPreference = screen.findPreference(getPreferenceKey()); + update(); + } + + @Override + public String getPreferenceKey() { + return KEY_BATTERY_SHARE; + } + + private void update() { + if (mPreference == null) return; + boolean enabled = !isPlugged(mContext) && wirelessCharger.isRtxSupported(); + mPreference.setEnabled(enabled); + ((TwoStatePreference) mPreference).setChecked(wirelessCharger.isRtxModeOn()); + } + + @Override + public int getAvailabilityStatus() { + return wirelessCharger.isRtxSupported() ? AVAILABLE : UNSUPPORTED_ON_DEVICE; + } + + @Override + public void updateState(Preference preference) { + update(); + } + + @Override + public boolean onPreferenceChange(Preference preference, Object newValue) { + wirelessCharger.setRtxMode((Boolean) newValue); + return true; + } + + @Override + public void onStart() { + IntentFilter filter = new IntentFilter(); + filter.addAction(Intent.ACTION_BATTERY_CHANGED); + mContext.registerReceiver(mBroadcastReceiver, filter); + } + + @Override + public void onStop() { + mContext.unregisterReceiver(mBroadcastReceiver); + } +} From 86e671c3e41e66881701380947ed570caee7d283 Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Fri, 15 Sep 2023 10:03:16 +0300 Subject: [PATCH 052/162] hide the "Storage manager" toggle from Storage screen "Storage manager" is supposed to automatically remove backed up photos and videos. This functionality is not implemented in AOSP, i.e. this toggle doesn't actually work. --- res/values/config.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/values/config.xml b/res/values/config.xml index 8c21fe4ed73..28d7036e7a3 100644 --- a/res/values/config.xml +++ b/res/values/config.xml @@ -618,7 +618,7 @@ content://com.android.providers.media.documents/root/others_root - true + false Allow running in background + "Warning: enabling this setting might cause some apps to stop working. + Allow access to Android/obb folder Required for installation of some large apps (mostly games) that use OBB expansion files diff --git a/src/com/android/settings/ext/AppPrefUtils.java b/src/com/android/settings/ext/AppPrefUtils.java new file mode 100644 index 00000000000..3ae426bf36f --- /dev/null +++ b/src/com/android/settings/ext/AppPrefUtils.java @@ -0,0 +1,14 @@ +package com.android.settings.ext; + +import android.content.Context; + +import com.android.settings.R; + +import androidx.annotation.StringRes; + +public class AppPrefUtils { + + public static String getFooterForDefaultHardeningSetting(Context ctx, @StringRes int baseText) { + return ctx.getString(R.string.app_exploit_protection_default_value_warning) + "\n\n" + ctx.getString(baseText); + } +} From d84628825243ad88df70b579113339d55e94e37f Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Wed, 15 Nov 2023 13:44:08 +0200 Subject: [PATCH 054/162] add base class for App info single-choice fragments --- .../appinfo/RadioButtonAppInfoFragment.java | 228 ++++++++++++++++++ 1 file changed, 228 insertions(+) create mode 100644 src/com/android/settings/applications/appinfo/RadioButtonAppInfoFragment.java diff --git a/src/com/android/settings/applications/appinfo/RadioButtonAppInfoFragment.java b/src/com/android/settings/applications/appinfo/RadioButtonAppInfoFragment.java new file mode 100644 index 00000000000..26fa78beb4d --- /dev/null +++ b/src/com/android/settings/applications/appinfo/RadioButtonAppInfoFragment.java @@ -0,0 +1,228 @@ +package com.android.settings.applications.appinfo; + +import android.content.Context; +import android.content.Intent; +import android.content.pm.ApplicationInfo; +import android.net.Uri; +import android.os.Bundle; +import android.util.TypedValue; + +import androidx.annotation.Nullable; +import androidx.annotation.StringRes; +import androidx.appcompat.app.AlertDialog; +import androidx.preference.Preference; +import androidx.preference.PreferenceScreen; +import androidx.preference.SwitchPreferenceCompat; + +import com.android.settings.applications.AppInfoWithHeader; +import com.android.settings.applications.SpacePreference; +import com.android.settingslib.widget.FooterPreference; +import com.android.settingslib.widget.SelectorWithWidgetPreference; + +import java.util.Collections; +import java.util.List; + +public abstract class RadioButtonAppInfoFragment extends AppInfoWithHeader implements SelectorWithWidgetPreference.OnClickListener { + + public static class Entry { + public final int id; + public CharSequence title; + @Nullable + public CharSequence summary; + public boolean isChecked; + public boolean isEnabled; + + public Entry(int id, CharSequence title, @Nullable CharSequence summary, boolean isChecked, boolean isEnabled) { + this.id = id; + this.title = title; + this.summary = summary; + this.isChecked = isChecked; + this.isEnabled = isEnabled; + } + } + + public static Entry createEntry(int id, CharSequence title) { + return new Entry(id, title, null, false, true); + } + + public Entry createEntry(int id, @StringRes int title) { + return createEntry(id, getText(title)); + } + + public Entry createEntry(@StringRes int title) { + return createEntry(title, title); + } + + public abstract Entry[] getEntries(); + + public boolean hasFooter() { + return true; + } + + public abstract void updateFooter(FooterPreference fp); + + public void setLearnMoreLink(FooterPreference p, String url) { + p.setLearnMoreAction(v -> { + var i = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); + startActivity(i); + }); + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + PreferenceScreen screen = getPreferenceManager().createPreferenceScreen(getPrefContext()); + setPreferenceScreen(screen); + requireActivity().setTitle(getTitle()); + } + + protected abstract CharSequence getTitle(); + + @Nullable + private SelectorWithWidgetPreference[] radioButtons; + @Nullable + private FooterPreference footer; + + private Preference[] extraPrefs; + + @Override + protected boolean refreshUi() { + Entry[] entries = getEntries(); + int entryCnt = entries.length; + + Context ctx = getPrefContext(); + PreferenceScreen screen = getPreferenceScreen(); + + if (radioButtons == null || radioButtons.length != entryCnt) { + if (radioButtons != null) { + for (Preference p : radioButtons) { + screen.removePreference(p); + } + } + + radioButtons = new SelectorWithWidgetPreference[entryCnt]; + + for (int i = 0; i < entryCnt; ++i) { + var p = new SelectorWithWidgetPreference(ctx); + p.setOnClickListener(this); + screen.addPreference(p); + radioButtons[i] = p; + } + } + + for (int i = 0; i < entryCnt; ++i) { + SelectorWithWidgetPreference p = radioButtons[i]; + Entry e = entries[i]; + p.setKey(Integer.toString(e.id)); + p.setTitle(e.title); + p.setSummary(e.summary); + p.setEnabled(e.isEnabled); + p.setChecked(e.isChecked); + } + + List extraPrefModels = getExtraPrefModels(); + + if (extraPrefs == null) { + if (extraPrefModels.isEmpty()) { + extraPrefs = new Preference[0]; + } else { + var spacer = new SpacePreference(ctx, null); + int h = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, 48f, ctx.getResources().getDisplayMetrics()); + spacer.setHeight(h); + screen.addPreference(spacer); + + extraPrefs = new Preference[extraPrefModels.size()]; + for (int i = 0; i < extraPrefs.length; ++i) { + PrefModel pm = extraPrefModels.get(i); + Preference p; + if (pm instanceof LinkPrefModel lpm) { + p = new Preference(ctx); + p.setOnPreferenceClickListener(pref -> { + lpm.onClick.run(); + return true; + }); + } else if (pm instanceof TogglePrefModel tpm) { + p = new SwitchPreferenceCompat(ctx); + p.setOnPreferenceChangeListener(tpm.onChangeListener); + } else { + throw new IllegalArgumentException(pm.toString()); + } + p.setKey("extra_pref_" + i); + screen.addPreference(p); + extraPrefs[i] = p; + } + } + } + for (int i = 0; i < extraPrefs.length; ++i) { + PrefModel pm = extraPrefModels.get(i); + Preference p = extraPrefs[i]; + if (pm instanceof TogglePrefModel tpm) { + var sp = (SwitchPreferenceCompat) p; + sp.setChecked(tpm.isChecked); + } + p.setTitle(pm.title); + p.setSummary(pm.summary); + p.setEnabled(pm.isEnabled); + } + + if (hasFooter()) { + if (footer == null) { + footer = new FooterPreference(ctx); + screen.addPreference(footer); + } + updateFooter(footer); + } else { + if (footer != null) { + screen.removePreference(footer); + footer = null; + } + } + + return true; + } + + public static class PrefModel { + public CharSequence title; + public CharSequence summary; + public boolean isEnabled = true; + } + + public static class LinkPrefModel extends PrefModel { + public Runnable onClick; + } + + public static class TogglePrefModel extends PrefModel { + public boolean isChecked; + public Preference.OnPreferenceChangeListener onChangeListener; + } + + protected List getExtraPrefModels() { + return Collections.emptyList(); + } + + @Override + public final void onRadioButtonClicked(SelectorWithWidgetPreference emiter) { + int id = Integer.parseInt(emiter.getKey()); + onEntrySelected(id); + if (!refreshUi()) { + setIntentAndFinish(true); + } + } + + public abstract void onEntrySelected(int id); + + @Override + protected AlertDialog createDialog(int id, int errorCode) { + return null; + } + + @Override + public int getMetricsCategory() { + return METRICS_CATEGORY_UNKNOWN; + } + + protected ApplicationInfo getAppInfo() { + return mPackageInfo.applicationInfo; + } +} From 52593632ba95c5b73642b46d41140f464ad05fec Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Wed, 15 Nov 2023 13:44:23 +0200 Subject: [PATCH 055/162] infrastructure for AppSwitch UIs Squashed with 28baa8dcbf5a0d285d8bf3852b723beaa290a973 by quh4gko8 <88831734+quh4gko8@users.noreply.github.com> --- res/values/strings_app_exploit_protection.xml | 37 +++ .../settings/applications/AswAdapter.kt | 88 +++++++ .../applications/AswAppInfoFragment.java | 228 ++++++++++++++++++ .../AswAppListPrefController.java | 27 +++ .../AswExploitProtectionFragment.java | 44 ++++ .../spa/app/appinfo/AppInfoSettings.kt | 3 + .../settings/spa/app/appinfo/AswAppList.kt | 101 ++++++++ .../settings/spa/app/appinfo/AswPreference.kt | 27 +++ .../spa/app/appinfo/PackageInfoPresenter.kt | 5 +- 9 files changed, 559 insertions(+), 1 deletion(-) create mode 100644 res/values/strings_app_exploit_protection.xml create mode 100644 src/com/android/settings/applications/AswAdapter.kt create mode 100644 src/com/android/settings/applications/AswAppInfoFragment.java create mode 100644 src/com/android/settings/applications/AswAppListPrefController.java create mode 100644 src/com/android/settings/applications/AswExploitProtectionFragment.java create mode 100644 src/com/android/settings/spa/app/appinfo/AswAppList.kt create mode 100644 src/com/android/settings/spa/app/appinfo/AswPreference.kt diff --git a/res/values/strings_app_exploit_protection.xml b/res/values/strings_app_exploit_protection.xml new file mode 100644 index 00000000000..5081ee0a037 --- /dev/null +++ b/res/values/strings_app_exploit_protection.xml @@ -0,0 +1,37 @@ + + + Exploit protection + + Allowed + Blocked + Default (%1$s) + Disabled + Enabled + Restricted + + Warning + This setting will weaken exploit protections for the selected app. + Proceed + + Default value can be changed in the %1$s section + + The selected app is known to be compatible with this setting + %1$s by default, because this app is known to need it. +This behavior can be disabled in the %2$s section. + + %1$s by default because this app depends on Play services + + Block for third-party apps by default + Restrict for third-party apps by default + Disable for third-party apps by default + Restricted by default + Restricted by default, except for apps that depend on Play services + Disabled by default + Blocked by default + Allowed for third-party apps by default + Enabled for third-party apps by default + + %1$s is enabled + + Exploit protection compatibility mode + diff --git a/src/com/android/settings/applications/AswAdapter.kt b/src/com/android/settings/applications/AswAdapter.kt new file mode 100644 index 00000000000..478dd02e25e --- /dev/null +++ b/src/com/android/settings/applications/AswAdapter.kt @@ -0,0 +1,88 @@ +package com.android.settings.applications + +import android.content.Context +import android.content.pm.ApplicationInfo +import android.content.pm.GosPackageState +import android.ext.settings.app.AppSwitch +import androidx.preference.Preference +import androidx.preference.PreferenceScreen +import com.android.settings.R +import com.android.settings.SettingsPreferenceFragment +import com.android.settings.applications.appinfo.AppInfoDashboardFragment +import com.android.settings.spa.SpaActivity.Companion.startSpaActivity +import com.android.settings.spa.app.appinfo.AppInfoSettingsProvider +import com.android.settings.spa.app.appinfo.AswAppListPageProvider +import com.android.settingslib.spaprivileged.model.app.userId +import kotlin.reflect.KClass + +abstract class AswAdapter { + abstract fun getAppSwitch(): T + + enum class Category { + ExploitProtection, + } + + fun getCategory(): Category = Category.ExploitProtection + + fun getPreferenceSummary(ctx: Context, appInfo: ApplicationInfo): CharSequence { + val asw = getAppSwitch() + val si = AppSwitch.StateInfo() + val userId = appInfo.userId + val isOn = asw.get(ctx, userId, appInfo, GosPackageState.get(appInfo.packageName, userId), si) + return if (si.isUsingDefaultValue) { + getDefaultTitle(ctx, isOn) + } else { + if (isOn) getOnTitle(ctx) else getOffTitle(ctx) + } + } + + open fun getNotificationToggleTitle(ctx: Context): CharSequence? = null + open fun getNotificationToggleSummary(ctx: Context): CharSequence? = null + + abstract fun getAswTitle(ctx: Context): CharSequence + + open fun getShortAswTitle(ctx: Context) = getAswTitle(ctx) + + fun getDefaultTitle(ctx: Context, isOn: Boolean): CharSequence { + return ctx.getString(R.string.aep_default, + if (isOn) getOnTitle(ctx) else getOffTitle(ctx) + ) + } + + open fun getOnTitle(ctx: Context): CharSequence = ctx.getText(R.string.aep_enabled) + + open fun getOffTitle(ctx: Context): CharSequence = ctx.getText(R.string.aep_disabled) + + abstract fun getDetailFragmentClass(): KClass + + fun openAppPage(context: Context, app: ApplicationInfo) { + AppInfoDashboardFragment.startAppInfoFragment( + getDetailFragmentClass().java, + app, context, AppInfoSettingsProvider.METRICS_CATEGORY, + ) + } + + fun makeAppListPageProvider() = AswAppListPageProvider(this) + + fun getAppListPageProviderName() = this::class.simpleName!! + + open fun shouldIncludeInAppListPage(app: ApplicationInfo, gosPs: GosPackageState) = true + + fun openAppListPage(ctx: Context) { + ctx.startSpaActivity(getAppListPageProviderName()) + } + + @JvmOverloads + fun addAppListPageLink(screen: PreferenceScreen, + title: CharSequence = screen.context.getText(R.string.default_see_all_apps_title)) { + val ctx = screen.context + val pref = Preference(ctx).apply { + this.title = title + setOnPreferenceClickListener { p -> + p.context.startSpaActivity(getAppListPageProviderName()) + true + } + } + screen.addPreference(pref) + } +} diff --git a/src/com/android/settings/applications/AswAppInfoFragment.java b/src/com/android/settings/applications/AswAppInfoFragment.java new file mode 100644 index 00000000000..cac5229f781 --- /dev/null +++ b/src/com/android/settings/applications/AswAppInfoFragment.java @@ -0,0 +1,228 @@ +package com.android.settings.applications; + +import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.content.pm.GosPackageState; +import android.ext.settings.app.AppSwitch; +import android.os.Bundle; + +import androidx.annotation.Nullable; + +import com.android.settings.R; +import com.android.settings.applications.appinfo.RadioButtonAppInfoFragment; + +import java.util.ArrayList; +import java.util.List; + +public abstract class AswAppInfoFragment + extends RadioButtonAppInfoFragment { + + protected static final int ID_DEFAULT = 0; + protected static final int ID_ON = 1; + protected static final int ID_OFF = 2; + + public abstract AswAdapter getAswAdapter(); + + protected AswAdapter adapter; + private final ArrayList extraPrefs = new ArrayList<>(); + @Nullable + private TogglePrefModel notifTogglePref; + + @Override + public void onCreate(Bundle savedInstanceState) { + adapter = getAswAdapter(); + super.onCreate(savedInstanceState); + + if (adapter.getAppSwitch().hasNotification()) { + Context ctx = requireContext(); + var p = new TogglePrefModel(); + p.title = adapter.getNotificationToggleTitle(ctx); + p.summary = adapter.getNotificationToggleSummary(ctx); + p.onChangeListener = (pref, state) -> { + var ed = GosPackageState.edit(mPackageName, mUserId); + adapter.getAppSwitch().setNotificationEnabled(ed, (boolean) state); + return ed.apply(); + }; + extraPrefs.add(p); + notifTogglePref = p; + } + { + var p = new LinkPrefModel(); + p.title = getText(R.string.default_see_all_apps_title); + p.onClick = () -> adapter.openAppListPage(requireContext()); + extraPrefs.add(p); + } + } + + @Override + protected CharSequence getTitle() { + return adapter.getAswTitle(requireContext()); + } + + @Override + public Entry[] getEntries() { + Context ctx = requireContext(); + AppSwitch asw = adapter.getAppSwitch(); + + int userId = mUserId; + GosPackageState ps = GosPackageState.get(mPackageName, userId); + ApplicationInfo appInfo = getAppInfo(); + var si = new AppSwitch.StateInfo(); + boolean state = asw.get(ctx, userId, appInfo, ps, si); + + boolean isDefault = si.isUsingDefaultValue(); + boolean isImmutable = si.isImmutable(); + + var defaultSi = new AppSwitch.StateInfo(); + boolean defaultValue = asw.getDefaultValue(ctx, userId, appInfo, ps, defaultSi); + + var def = createEntry(ID_DEFAULT, adapter.getDefaultTitle(ctx, defaultValue)); + def.isChecked = isDefault; + def.isEnabled = !isImmutable; + if (def.isEnabled) { + int dvr = defaultSi.getDefaultValueReason(); + CharSequence summary = getSummaryForDefaultValueReason(dvr); + if (summary == null) { + summary = switch (dvr) { + case AppSwitch.DVR_DEFAULT_SETTING -> { + if (!ctx.getUser().isSystem()) { + yield null; + } + yield getString(R.string.aep_dvr_default_security_setting, + getAppDefaultSettingPathForCategory(adapter.getCategory())); + } + case AppSwitch.DVR_APP_COMPAT_CONFIG_HARDENING_OPT_IN -> + getText(R.string.aep_dvr_compat_config_hardening_opt_in); + case AppSwitch.DVR_APP_COMPAT_CONFIG_HARDENING_OPT_OUT -> { + if (!ctx.getUser().isSystem()) { + yield null; + } + var s = defaultValue ? adapter.getOnTitle(ctx) : adapter.getOffTitle(ctx); + yield getString(R.string.aep_dvr_compat_config_hardening_opt_out, + s.toString(), getSettingPath(R.string.safety_center_title, + R.string.more_security_privacy_settings)); + } + case AppSwitch.DVR_APP_IS_CLIENT_OF_GMSCORE -> { + var s = defaultValue ? adapter.getOnTitle(ctx) : adapter.getOffTitle(ctx); + yield getString(R.string.aep_dvr_app_is_client_of_gmscore, s.toString()); + } + default -> null; + }; + } + def.summary = summary; + } + + var enabled = createEntry(ID_ON, adapter.getOnTitle(ctx)); + enabled.isChecked = !isDefault && state; + enabled.isEnabled = enabled.isChecked || !isImmutable; + + var disabled = createEntry(ID_OFF, adapter.getOffTitle(ctx)); + disabled.isChecked = !isDefault && !state; + disabled.isEnabled = disabled.isChecked || !isImmutable; + + if (isImmutable) { + int immutabilityReason = si.getImmutabilityReason(); + CharSequence summary = getSummaryForImmutabilityReason(immutabilityReason); + if (summary == null) { + if (immutabilityReason == AppSwitch.IR_EXPLOIT_PROTECTION_COMPAT_MODE) { + summary = getString(R.string.aep_ir_exploit_protection_compat_mode, + getString(R.string.aep_compat_mode_title)); + } + } + if (enabled.isChecked) { + enabled.summary = summary; + } + if (disabled.isChecked) { + disabled.summary = summary; + } + } + + if (notifTogglePref != null) { + notifTogglePref.isChecked = adapter.getAppSwitch().isNotificationEnabled(ps); + notifTogglePref.isEnabled = state; + } + + return new Entry[] { def, enabled, disabled }; + } + + private String getAppDefaultSettingPathForCategory(AswAdapter.Category category) { + switch (category) { + case ExploitProtection: + return getSettingPath(R.string.safety_center_title, R.string.exploit_protection_settings); + default: + throw new IllegalArgumentException(category.toString()); + } + } + + private String getSettingPath(int... parts) { + var sb = new StringBuilder(); + for (int i = 0; i < parts.length; ++i) { + if (i != 0) { + sb.append(" > "); + } + sb.append(getString(parts[i])); + } + return sb.toString(); + } + + @Nullable + protected CharSequence getSummaryForDefaultValueReason(int dvr) { + return null; + } + + @Nullable + protected CharSequence getSummaryForImmutabilityReason(int ir) { + return null; + } + + @Override + protected List getExtraPrefModels() { + return extraPrefs; + } + + @Override + public final void onEntrySelected(int id) { + Context ctx = requireContext(); + AppSwitch asw = adapter.getAppSwitch(); + int userId = mUserId; + String pkgName = mPackageName; + GosPackageState ps = GosPackageState.get(pkgName, userId); + ApplicationInfo appInfo = getAppInfo(); + + boolean isImmutable = asw.isImmutable(ctx, userId, appInfo, ps); + + if (isImmutable) { + return; + } + + Runnable r = () -> { + GosPackageState.Editor ed = GosPackageState.edit(pkgName, userId); + + switch (id) { + case ID_DEFAULT -> asw.setUseDefaultValue(ed); + case ID_ON, ID_OFF -> asw.set(ed, id == ID_ON); + default -> throw new IllegalStateException(); + } + + ed.setKillUidAfterApply(shouldKillUidAfterChange()); + + if (!ed.apply()) { + finish(); + } + + if (!refreshUi()) { + setIntentAndFinish(true); + } + }; + + completeStateChange(id, asw.get(ctx, userId, appInfo, ps), r); + } + + protected void completeStateChange(int newEntryId, boolean curValue, Runnable stateChangeAction) { + stateChangeAction.run(); + } + + protected boolean shouldKillUidAfterChange() { + return true; + } +} diff --git a/src/com/android/settings/applications/AswAppListPrefController.java b/src/com/android/settings/applications/AswAppListPrefController.java new file mode 100644 index 00000000000..c6d9fa7260a --- /dev/null +++ b/src/com/android/settings/applications/AswAppListPrefController.java @@ -0,0 +1,27 @@ +package com.android.settings.applications; + +import android.content.Context; + +import androidx.preference.Preference; + +import com.android.settings.applications.AswAdapter; +import com.android.settings.core.BasePreferenceController; + +public abstract class AswAppListPrefController extends BasePreferenceController { + + protected final AswAdapter aswAdapter; + + public AswAppListPrefController(Context context, String preferenceKey, AswAdapter adapter) { + super(context, preferenceKey); + aswAdapter = adapter; + } + + @Override + public boolean handlePreferenceTreeClick(Preference preference) { + if (!getPreferenceKey().equals(preference.getKey())) { + return false; + } + aswAdapter.openAppListPage(preference.getContext()); + return true; + } +} diff --git a/src/com/android/settings/applications/AswExploitProtectionFragment.java b/src/com/android/settings/applications/AswExploitProtectionFragment.java new file mode 100644 index 00000000000..19d0a470433 --- /dev/null +++ b/src/com/android/settings/applications/AswExploitProtectionFragment.java @@ -0,0 +1,44 @@ +package com.android.settings.applications; + +import android.content.Context; +import android.content.pm.GosPackageState; +import android.ext.settings.app.AppSwitch; + +import androidx.appcompat.app.AlertDialog; + +import com.android.settings.R; + +public abstract class AswExploitProtectionFragment extends AswAppInfoFragment { + + @Override + protected void completeStateChange(int newEntryId, boolean curValue, Runnable stateChangeAction) { + Context ctx = requireContext(); + + boolean showWarning = false; + if (curValue) { + if (newEntryId == ID_OFF) { + showWarning = true; + } else if (newEntryId == ID_DEFAULT) { + AppSwitch asw = adapter.getAppSwitch(); + int userId = mUserId; + var ps = GosPackageState.get(mPackageName, userId); + showWarning = !asw.getDefaultValue(ctx, userId, getAppInfo(), ps); + } + } + if (showWarning) { + var d = getExploitProtectionWarningOnDisable(ctx, stateChangeAction); + d.show(); + } else { + stateChangeAction.run(); + } + } + + public static AlertDialog.Builder getExploitProtectionWarningOnDisable(Context ctx, Runnable action) { + var b = new AlertDialog.Builder(ctx); + b.setTitle(R.string.aep_confirm_disable_title); + b.setMessage(R.string.aep_confirm_disable_warning_msg); + b.setNegativeButton(R.string.cancel, null); + b.setPositiveButton(R.string.aep_confirm_disable_proceed_btn, (d, w) -> action.run()); + return b; + } +} diff --git a/src/com/android/settings/spa/app/appinfo/AppInfoSettings.kt b/src/com/android/settings/spa/app/appinfo/AppInfoSettings.kt index 391a21273d8..3dbf7caf66e 100644 --- a/src/com/android/settings/spa/app/appinfo/AppInfoSettings.kt +++ b/src/com/android/settings/spa/app/appinfo/AppInfoSettings.kt @@ -46,6 +46,7 @@ import com.android.settings.spa.app.specialaccess.PictureInPictureListProvider import com.android.settings.spa.app.specialaccess.UsageDataAppListProvider import com.android.settings.spa.app.specialaccess.WriteSystemPreferencesAppListProvider import com.android.settingslib.spa.framework.common.SettingsPageProvider +import com.android.settingslib.spa.framework.compose.LifecycleEffect import com.android.settingslib.spa.framework.compose.navigator import com.android.settingslib.spa.widget.scaffold.RegularScaffold import com.android.settingslib.spa.widget.ui.Category @@ -121,6 +122,8 @@ object AppInfoSettingsProvider : SettingsPageProvider { @Composable private fun AppInfoSettings(packageInfoPresenter: PackageInfoPresenter) { + // needed to refresh AppSwitch items after returning from their fragments + LifecycleEffect(onStart = { check(packageInfoPresenter.manualRefreshFlow.tryEmit(Any())) }) val packageInfoState = packageInfoPresenter.flow.collectAsStateWithLifecycle() val featureFlags: PmFeatureFlags = PmFeatureFlagsImpl() RegularScaffold( diff --git a/src/com/android/settings/spa/app/appinfo/AswAppList.kt b/src/com/android/settings/spa/app/appinfo/AswAppList.kt new file mode 100644 index 00000000000..c08586a7002 --- /dev/null +++ b/src/com/android/settings/spa/app/appinfo/AswAppList.kt @@ -0,0 +1,101 @@ +package com.android.settings.spa.app.appinfo + +import android.content.Context +import android.content.pm.ApplicationInfo +import android.content.pm.GosPackageState +import android.os.Bundle +import androidx.compose.runtime.Composable +import androidx.compose.ui.platform.LocalContext +import com.android.settings.applications.AswAdapter +import com.android.settingslib.spa.framework.common.SettingsPageProvider +import com.android.settingslib.spa.framework.compose.rememberContext +import com.android.settingslib.spa.framework.util.asyncFilter +import com.android.settingslib.spa.framework.util.asyncMap +import com.android.settingslib.spa.widget.ui.SpinnerOption +import com.android.settingslib.spaprivileged.model.app.AppListModel +import com.android.settingslib.spaprivileged.model.app.AppRecord +import com.android.settingslib.spaprivileged.template.app.AppListItem +import com.android.settingslib.spaprivileged.template.app.AppListItemModel +import com.android.settingslib.spaprivileged.template.app.AppListPage +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.combine + +open class AswAppListPageProvider(val adapter: AswAdapter<*>) : SettingsPageProvider { + override val name = adapter.getAppListPageProviderName() + + @Composable + override fun Page(arguments: Bundle?) { + AswAppListPage(adapter) + } +} + +@Composable +fun AswAppListPage(adapter: AswAdapter<*>) { + AppListPage( + title = rememberContext { ctx -> + adapter.getShortAswTitle(ctx).toString() + }, + listModel = rememberContext { ctx -> + AswAppListModel(ctx, adapter) + }, + ) +} + +class AppRecordImpl(override val app: ApplicationInfo, val gosPackageState: GosPackageState) : AppRecord + +class AswAppListModel(val ctx: Context, val adapter: AswAdapter<*>) : AppListModel { + companion object { + const val SPINNER_OPTION_OFF = 0 + const val SPINNER_OPTION_ON = 1 + } + + override fun getSpinnerOptions(recordList: List): List { + val options = ArrayList(2) + options.add(SpinnerOption(SPINNER_OPTION_OFF, adapter.getOffTitle(ctx).toString())) + options.add(SpinnerOption(SPINNER_OPTION_ON, adapter.getOnTitle(ctx).toString())) + return options + } + + override fun transform( + userIdFlow: Flow, + appListFlow: Flow> + ): Flow> { + return userIdFlow.combine(appListFlow) { userId, appList -> + appList.asyncMap { app -> + val gosPs = GosPackageState.get(app.packageName, userId) + if (adapter.shouldIncludeInAppListPage(app, gosPs)) { + AppRecordImpl(app, GosPackageState.get(app.packageName, userId)) + } else { + null + } + }.filterNotNull() + } + } + + override fun filter( + userIdFlow: Flow, + option: Int, + recordListFlow: Flow> + ): Flow> { + val appSwitch = adapter.getAppSwitch() + return userIdFlow.combine(recordListFlow) { userId, recordList -> + recordList.asyncFilter { + val value = appSwitch.get(ctx, userId, it.app, it.gosPackageState) + when (option) { + SPINNER_OPTION_OFF -> !value + SPINNER_OPTION_ON -> value + else -> throw IllegalArgumentException(option.toString()) + } + } + } + } + + @Composable + override fun AppListItemModel.AppItem() { + val context = LocalContext.current + AppListItem(onClick = { + adapter.openAppPage(context, record.app) + }) + } +} + diff --git a/src/com/android/settings/spa/app/appinfo/AswPreference.kt b/src/com/android/settings/spa/app/appinfo/AswPreference.kt new file mode 100644 index 00000000000..116fa047025 --- /dev/null +++ b/src/com/android/settings/spa/app/appinfo/AswPreference.kt @@ -0,0 +1,27 @@ +package com.android.settings.spa.app.appinfo + +import android.content.Context +import android.content.pm.ApplicationInfo +import android.ext.settings.app.AppSwitch +import androidx.compose.runtime.Composable +import com.android.settings.applications.AswAdapter +import com.android.settingslib.spa.widget.preference.Preference +import com.android.settingslib.spa.widget.preference.PreferenceModel +import com.android.settingslib.spaprivileged.model.app.installed + +@Composable +fun AswPreference(context: Context, app: ApplicationInfo, adapter: AswAdapter) { + if (!app.installed) { + return + } + + Preference(object : PreferenceModel { + override val title = adapter.getAswTitle(context).toString() + override val summary = { + adapter.getPreferenceSummary(context, app).toString() + } + override val onClick = { + adapter.openAppPage(context, app) + } + }) +} diff --git a/src/com/android/settings/spa/app/appinfo/PackageInfoPresenter.kt b/src/com/android/settings/spa/app/appinfo/PackageInfoPresenter.kt index 8785fe821af..a08e6b6e740 100644 --- a/src/com/android/settings/spa/app/appinfo/PackageInfoPresenter.kt +++ b/src/com/android/settings/spa/app/appinfo/PackageInfoPresenter.kt @@ -44,6 +44,7 @@ import com.android.settingslib.spaprivileged.model.app.IPackageManagers import com.android.settingslib.spaprivileged.model.app.PackageManagers import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.filter @@ -96,7 +97,9 @@ class PackageInfoPresenter( intent.action != Intent.ACTION_PACKAGE_REMOVED || intent.getBooleanExtra(Intent.EXTRA_ARCHIVAL, false) - val flow: StateFlow = merge(flowOf(null), appChangeFlow) + val manualRefreshFlow = MutableStateFlow(null) + + val flow: StateFlow = merge(flowOf(null), appChangeFlow, manualRefreshFlow) .map { getPackageInfo() } .stateIn(coroutineScope + Dispatchers.Default, SharingStarted.Eagerly, null) From f9c66473fdf5498111caa4d2528d3dcd0c6e1e23 Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Sat, 2 Mar 2024 12:09:48 +0200 Subject: [PATCH 056/162] add "Exploit protection" category to App info --- src/com/android/settings/spa/app/appinfo/AppInfoSettings.kt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/com/android/settings/spa/app/appinfo/AppInfoSettings.kt b/src/com/android/settings/spa/app/appinfo/AppInfoSettings.kt index 3dbf7caf66e..6ccdeabfc77 100644 --- a/src/com/android/settings/spa/app/appinfo/AppInfoSettings.kt +++ b/src/com/android/settings/spa/app/appinfo/AppInfoSettings.kt @@ -181,6 +181,9 @@ private fun AppInfoSettings(packageInfoPresenter: PackageInfoPresenter) { UsageDataAppListProvider.InfoPageEntryItem(app) } + Category(title = stringResource(R.string.exploit_protection_category_title)) { + } + Category(title = stringResource(R.string.app_install_details_group_title)) { AppInstallerInfoPreference(app) } From 0bc856dd4dd56e1e688e143c4bb6cdcae70e4c87 Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Tue, 26 Sep 2023 10:34:50 +0300 Subject: [PATCH 057/162] add per-app setting for exploit protection compatibility mode --- res/values/strings_app_exploit_protection.xml | 1 + ...oitProtectionCompatModeSwitchPreference.kt | 59 +++++++++++++++++++ .../spa/app/appinfo/AppInfoSettings.kt | 1 + 3 files changed, 61 insertions(+) create mode 100644 src/com/android/settings/spa/app/appinfo/AppExploitProtectionCompatModeSwitchPreference.kt diff --git a/res/values/strings_app_exploit_protection.xml b/res/values/strings_app_exploit_protection.xml index 5081ee0a037..ed4eef3ab79 100644 --- a/res/values/strings_app_exploit_protection.xml +++ b/res/values/strings_app_exploit_protection.xml @@ -34,4 +34,5 @@ This behavior can be disabled in the %2$s section. %1$s is enabled Exploit protection compatibility mode + Improves compatibility by disabling some of the GrapheneOS exploit protections for this app diff --git a/src/com/android/settings/spa/app/appinfo/AppExploitProtectionCompatModeSwitchPreference.kt b/src/com/android/settings/spa/app/appinfo/AppExploitProtectionCompatModeSwitchPreference.kt new file mode 100644 index 00000000000..daf3ace3dba --- /dev/null +++ b/src/com/android/settings/spa/app/appinfo/AppExploitProtectionCompatModeSwitchPreference.kt @@ -0,0 +1,59 @@ +package com.android.settings.spa.app.appinfo + +import android.content.pm.ApplicationInfo +import android.content.pm.GosPackageState +import android.content.pm.GosPackageStateFlag +import androidx.compose.runtime.Composable +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.stringResource +import com.android.settings.R +import com.android.settings.applications.AswExploitProtectionFragment +import com.android.settingslib.spa.widget.preference.SwitchPreference +import com.android.settingslib.spa.widget.preference.SwitchPreferenceModel +import com.android.settingslib.spaprivileged.model.app.installed +import com.android.settingslib.spaprivileged.model.app.userId + +@Composable +fun AppExploitProtectionCompatModeSwitchPreference(app: ApplicationInfo, + packageInfoPresenter: PackageInfoPresenter) { + if (app.isSystemApp || !app.installed) { + return + } + + val context = LocalContext.current + val pkgName = app.packageName + val userId = app.userId + val psFlag = GosPackageStateFlag.ENABLE_EXPLOIT_PROTECTION_COMPAT_MODE + + SwitchPreference(object : SwitchPreferenceModel { + override val title = stringResource(R.string.aep_compat_mode_title) + override val summary = { + context.getString(R.string.aep_compat_mode_summary) + } + + override val checked = { + GosPackageState.get(pkgName, userId).hasFlag(psFlag) + } + + override val onCheckedChange = { newChecked: Boolean -> + val action = Runnable { + GosPackageState.edit(pkgName, userId).run { + setFlagState(psFlag, newChecked) + killUidAfterApply() + if (apply()) { + // needed to recompose other exploit protection settings + check(packageInfoPresenter.manualRefreshFlow.tryEmit(Any())) + } + } + } + + if (newChecked) { + val d = AswExploitProtectionFragment.getExploitProtectionWarningOnDisable(context, action) + d.show() + } else { + action.run() + } + Unit + } + }) +} diff --git a/src/com/android/settings/spa/app/appinfo/AppInfoSettings.kt b/src/com/android/settings/spa/app/appinfo/AppInfoSettings.kt index 6ccdeabfc77..0d6ce0a7dd6 100644 --- a/src/com/android/settings/spa/app/appinfo/AppInfoSettings.kt +++ b/src/com/android/settings/spa/app/appinfo/AppInfoSettings.kt @@ -182,6 +182,7 @@ private fun AppInfoSettings(packageInfoPresenter: PackageInfoPresenter) { } Category(title = stringResource(R.string.exploit_protection_category_title)) { + AppExploitProtectionCompatModeSwitchPreference(app, packageInfoPresenter) } Category(title = stringResource(R.string.app_install_details_group_title)) { From a75ecbd1942992e9d43dcd7d277a22a24bd1ba8a Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Sat, 7 Oct 2023 21:28:08 +0300 Subject: [PATCH 058/162] add toggle for automatic exploit protection compatibility mode --- res/values/strings_ext.xml | 6 ++++++ res/xml/more_security_privacy_settings.xml | 7 +++++++ 2 files changed, 13 insertions(+) diff --git a/res/values/strings_ext.xml b/res/values/strings_ext.xml index e2ef48368dd..219e9dfd244 100644 --- a/res/values/strings_ext.xml +++ b/res/values/strings_ext.xml @@ -124,6 +124,12 @@ There are HTTP, HTTPS, DNS, DNS-over-TLS and DNS-over-HTTPS connectivity checks. Allow running in background + Automatic exploit protection compatibility mode + + +"Allow automatically disabling exploit protections for apps that are known to need it" + + "Warning: enabling this setting might cause some apps to stop working. Allow access to Android/obb folder diff --git a/res/xml/more_security_privacy_settings.xml b/res/xml/more_security_privacy_settings.xml index adf0d09c604..025f1c20755 100644 --- a/res/xml/more_security_privacy_settings.xml +++ b/res/xml/more_security_privacy_settings.xml @@ -235,6 +235,13 @@ settings:keywords="@string/keywords_app_pinning" settings:controller="com.android.settings.security.ScreenPinningPreferenceController" /> + + Date: Thu, 16 Nov 2023 17:23:47 +0200 Subject: [PATCH 059/162] add per-app setting for hardened_malloc --- AndroidManifest.xml | 18 +++++++ res/values/strings_app_exploit_protection.xml | 8 +++ res/xml/exploit_protection_settings.xml | 5 ++ src/com/android/settings/Settings.java | 2 + .../applications/AppHardenedMalloc.kt | 54 +++++++++++++++++++ .../core/gateway/SettingsGateway.java | 1 + .../settings/spa/SettingsSpaEnvironment.kt | 1 + .../spa/app/appinfo/AppInfoSettings.kt | 1 + 8 files changed, 90 insertions(+) create mode 100644 src/com/android/settings/applications/AppHardenedMalloc.kt diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 49d0b5905bc..811db2d6a54 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -6040,5 +6040,23 @@ + + + + + + + + + + + + + diff --git a/res/values/strings_app_exploit_protection.xml b/res/values/strings_app_exploit_protection.xml index ed4eef3ab79..8581d72090b 100644 --- a/res/values/strings_app_exploit_protection.xml +++ b/res/values/strings_app_exploit_protection.xml @@ -35,4 +35,12 @@ This behavior can be disabled in the %2$s section. Exploit protection compatibility mode Improves compatibility by disabling some of the GrapheneOS exploit protections for this app + + Hardened memory allocator + + Hardened memory allocator (hardened_malloc) provides substantial defenses against the most common classes of vulnerabilities (heap memory corruption) along with reducing the lifetime of sensitive data in memory. + This app doesn’t have native code + This is a 32-bit app, hardened_malloc is 64-bit only + hardened_malloc is not allowed to be disabled for a preinstalled app + This is a debuggable app, hardened_malloc can’t be disabled diff --git a/res/xml/exploit_protection_settings.xml b/res/xml/exploit_protection_settings.xml index ada50481305..34d6ccf6cb4 100644 --- a/res/xml/exploit_protection_settings.xml +++ b/res/xml/exploit_protection_settings.xml @@ -24,6 +24,11 @@ android:key="app_exploit_protection_settings" android:title="@string/app_exploit_protection_category"> + + () { + + override fun getAppSwitch() = AswUseHardenedMalloc.I + + override fun getAswTitle(ctx: Context) = ctx.getText(R.string.aep_hmalloc) + + override fun getDetailFragmentClass() = AppHardenedMallocFragment::class +} + +@Composable +fun AppHardenedMallocPreference(app: ApplicationInfo) { + val context = LocalContext.current + AswPreference(context, app, AswAdapterUseHardenedMalloc) +} + +class AppHardenedMallocFragment : AswExploitProtectionFragment() { + + override fun getAswAdapter() = AswAdapterUseHardenedMalloc + + override fun getSummaryForImmutabilityReason(ir: Int): CharSequence? { + val id = when (ir) { + AppSwitch.IR_IS_SYSTEM_APP -> R.string.aep_hmalloc_ir_preinstalled_app + AppSwitch.IR_NO_NATIVE_CODE -> R.string.aep_hmalloc_ir_no_native_code + AppSwitch.IR_NON_64_BIT_NATIVE_CODE -> R.string.aep_hmalloc_ir_32_bit_native_code + AppSwitch.IR_IS_DEBUGGABLE_APP -> R.string.aep_hmalloc_ir_debuggable_app + else -> return null + } + return getText(id) + } + + override fun updateFooter(fp: FooterPreference) { + fp.setTitle(R.string.aep_hmalloc_footer) + setLearnMoreLink(fp, "https://grapheneos.org/features#exploit-mitigations") + } +} + + +class HardenedMallocAppListPrefController(context: Context, preferenceKey: String) : + AswAppListPrefController(context, preferenceKey, AswAdapterUseHardenedMalloc) { + + override fun getAvailabilityStatus() = AVAILABLE +} diff --git a/src/com/android/settings/core/gateway/SettingsGateway.java b/src/com/android/settings/core/gateway/SettingsGateway.java index 2d3f63e9a5e..fc5421a9ef7 100644 --- a/src/com/android/settings/core/gateway/SettingsGateway.java +++ b/src/com/android/settings/core/gateway/SettingsGateway.java @@ -229,6 +229,7 @@ public class SettingsGateway { * security exception if the fragment it needs to display is not in this list. */ public static final String[] ENTRY_FRAGMENTS = { + com.android.settings.applications.AppHardenedMallocFragment.class.getName(), com.android.settings.safetycenter.ExploitProtectionFragment.class.getName(), AdvancedConnectedDeviceDashboardFragment.class.getName(), CreateShortcut.class.getName(), diff --git a/src/com/android/settings/spa/SettingsSpaEnvironment.kt b/src/com/android/settings/spa/SettingsSpaEnvironment.kt index ce95004f34d..2c85f69e8ce 100644 --- a/src/com/android/settings/spa/SettingsSpaEnvironment.kt +++ b/src/com/android/settings/spa/SettingsSpaEnvironment.kt @@ -101,6 +101,7 @@ open class SettingsSpaEnvironment(context: Context) : SpaEnvironment(context) { listOf( HomePageProvider, AppsMainPageProvider, + com.android.settings.applications.AswAdapterUseHardenedMalloc.makeAppListPageProvider(), AllAppListPageProvider, AppInfoSettingsProvider, SpecialAppAccessPageProvider, diff --git a/src/com/android/settings/spa/app/appinfo/AppInfoSettings.kt b/src/com/android/settings/spa/app/appinfo/AppInfoSettings.kt index 0d6ce0a7dd6..fbbf7d39300 100644 --- a/src/com/android/settings/spa/app/appinfo/AppInfoSettings.kt +++ b/src/com/android/settings/spa/app/appinfo/AppInfoSettings.kt @@ -183,6 +183,7 @@ private fun AppInfoSettings(packageInfoPresenter: PackageInfoPresenter) { Category(title = stringResource(R.string.exploit_protection_category_title)) { AppExploitProtectionCompatModeSwitchPreference(app, packageInfoPresenter) + com.android.settings.applications.AppHardenedMallocPreference(app) } Category(title = stringResource(R.string.app_install_details_group_title)) { From bfa68f17fdcf52358f65256531c5a80c995ac066 Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Fri, 30 Aug 2024 16:23:56 +0300 Subject: [PATCH 060/162] add dev mode per-app setting for extended virtual address space --- res/values/strings_app_exploit_protection.xml | 5 ++ res/xml/exploit_protection_settings.xml | 5 ++ .../applications/AppExtendedVaSpace.kt | 58 +++++++++++++++++++ .../settings/spa/SettingsSpaEnvironment.kt | 1 + .../spa/app/appinfo/AppInfoSettings.kt | 1 + 5 files changed, 70 insertions(+) create mode 100644 src/com/android/settings/applications/AppExtendedVaSpace.kt diff --git a/res/values/strings_app_exploit_protection.xml b/res/values/strings_app_exploit_protection.xml index 8581d72090b..d9d94fe5484 100644 --- a/res/values/strings_app_exploit_protection.xml +++ b/res/values/strings_app_exploit_protection.xml @@ -43,4 +43,9 @@ This behavior can be disabled in the %2$s section. This is a 32-bit app, hardened_malloc is 64-bit only hardened_malloc is not allowed to be disabled for a preinstalled app This is a debuggable app, hardened_malloc can’t be disabled + + Extended virtual address space + Extends virtual address space from 39 to 48 bits, which significantly improves the address space layout randomization. + Incompatible with 32-bit apps + Required by hardened_malloc diff --git a/res/xml/exploit_protection_settings.xml b/res/xml/exploit_protection_settings.xml index 34d6ccf6cb4..1068040a7a6 100644 --- a/res/xml/exploit_protection_settings.xml +++ b/res/xml/exploit_protection_settings.xml @@ -29,6 +29,11 @@ android:title="@string/aep_hmalloc" settings:controller="com.android.settings.applications.HardenedMallocAppListPrefController" /> + + () { + + override fun getAppSwitch() = AswUseExtendedVaSpace.I + + override fun getAswTitle(ctx: Context) = ctx.getText(R.string.aep_ext_va_space) + + override fun getDetailFragmentClass() = AppExtendedVaSpaceFragment::class +} + +@Composable +fun AppExtendedVaSpacePreference(app: ApplicationInfo) { + val context = LocalContext.current + if (ExtSettingControllerHelper.getDevModeSettingAvailability(context) != BasePreferenceController.AVAILABLE) { + return + } + + AswPreference(context, app, AswAdapterUseExtendedVaSpace) +} + +class AppExtendedVaSpaceFragment : AswExploitProtectionFragment() { + + override fun getAswAdapter() = AswAdapterUseExtendedVaSpace + + override fun getSummaryForImmutabilityReason(ir: Int): CharSequence? { + val id = when (ir) { + AppSwitch.IR_REQUIRED_BY_HARDENED_MALLOC -> R.string.aep_ext_va_space_ir_hardened_malloc + AppSwitch.IR_NON_64_BIT_NATIVE_CODE -> R.string.aep_ext_va_space_ir_32_bit_native_code + else -> return null + } + return getText(id) + } + + override fun updateFooter(fp: FooterPreference) { + fp.setTitle(R.string.aep_ext_va_space_footer) + } +} + + +class ExtendedVaSpaceAppListPrefController(context: Context, preferenceKey: String) : + AswAppListPrefController(context, preferenceKey, AswAdapterUseExtendedVaSpace) { + + override fun getAvailabilityStatus() = ExtSettingControllerHelper + .getDevModeSettingAvailability(mContext) +} diff --git a/src/com/android/settings/spa/SettingsSpaEnvironment.kt b/src/com/android/settings/spa/SettingsSpaEnvironment.kt index 2c85f69e8ce..7d3e08323c9 100644 --- a/src/com/android/settings/spa/SettingsSpaEnvironment.kt +++ b/src/com/android/settings/spa/SettingsSpaEnvironment.kt @@ -102,6 +102,7 @@ open class SettingsSpaEnvironment(context: Context) : SpaEnvironment(context) { HomePageProvider, AppsMainPageProvider, com.android.settings.applications.AswAdapterUseHardenedMalloc.makeAppListPageProvider(), + com.android.settings.applications.AswAdapterUseExtendedVaSpace.makeAppListPageProvider(), AllAppListPageProvider, AppInfoSettingsProvider, SpecialAppAccessPageProvider, diff --git a/src/com/android/settings/spa/app/appinfo/AppInfoSettings.kt b/src/com/android/settings/spa/app/appinfo/AppInfoSettings.kt index fbbf7d39300..1cf0ce258d1 100644 --- a/src/com/android/settings/spa/app/appinfo/AppInfoSettings.kt +++ b/src/com/android/settings/spa/app/appinfo/AppInfoSettings.kt @@ -184,6 +184,7 @@ private fun AppInfoSettings(packageInfoPresenter: PackageInfoPresenter) { Category(title = stringResource(R.string.exploit_protection_category_title)) { AppExploitProtectionCompatModeSwitchPreference(app, packageInfoPresenter) com.android.settings.applications.AppHardenedMallocPreference(app) + com.android.settings.applications.AppExtendedVaSpacePreference(app) } Category(title = stringResource(R.string.app_install_details_group_title)) { From 4fdf019774166d708c23436fac69180c9a17c3f1 Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Wed, 15 Nov 2023 13:51:07 +0200 Subject: [PATCH 061/162] add per-app setting for native debugging --- AndroidManifest.xml | 18 ++++ res/values/strings_app_exploit_protection.xml | 8 ++ res/xml/exploit_protection_settings.xml | 11 +++ src/com/android/settings/Settings.java | 2 + .../applications/AppNativeDebugging.kt | 94 +++++++++++++++++++ .../core/gateway/SettingsGateway.java | 1 + .../settings/spa/SettingsSpaEnvironment.kt | 1 + .../spa/app/appinfo/AppInfoSettings.kt | 1 + 8 files changed, 136 insertions(+) create mode 100644 src/com/android/settings/applications/AppNativeDebugging.kt diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 811db2d6a54..369ce4b1002 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -6041,6 +6041,24 @@ + + + + + + + + + + + + + Extends virtual address space from 39 to 48 bits, which significantly improves the address space layout randomization. Incompatible with 32-bit apps Required by hardened_malloc + + Native code debugging + Show notifications about blocked access attempts + +Native code debugging (ptrace) slightly weakens the app sandbox. Some apps (most notably banking apps) use it as a tampering detection tool. + + Native debugging is always blocked for preinstalled apps + diff --git a/res/xml/exploit_protection_settings.xml b/res/xml/exploit_protection_settings.xml index 1068040a7a6..c56c38ef64c 100644 --- a/res/xml/exploit_protection_settings.xml +++ b/res/xml/exploit_protection_settings.xml @@ -34,6 +34,17 @@ android:title="@string/aep_ext_va_space" settings:controller="com.android.settings.applications.ExtendedVaSpaceAppListPrefController" /> + + + + () { + + override fun getAppSwitch() = AswDenyNativeDebug.I + + override fun getAswTitle(ctx: Context) = ctx.getText(R.string.aep_native_debug_title) + + override fun getOnTitle(ctx: Context) = ctx.getText(R.string.aep_blocked) + override fun getOffTitle(ctx: Context) = ctx.getText(R.string.aep_allowed) + + override fun getNotificationToggleTitle(ctx: Context) = ctx.getText(R.string.aep_native_debug_notif_toggle_title) + + override fun getDetailFragmentClass() = AppNativeDebuggingFragment::class +} + +@Composable +fun AppNativeDebuggingPreference(app: ApplicationInfo) { + val context = LocalContext.current + AswPreference(context, app, AswAdapterNativeDebugging) +} + +class AppNativeDebuggingFragment : AswExploitProtectionFragment() { + + override fun getAswAdapter() = AswAdapterNativeDebugging + + override fun getSummaryForImmutabilityReason(ir: Int): CharSequence? { + val id = when (ir) { + AppSwitch.IR_IS_SYSTEM_APP -> R.string.aep_native_debug_dvr_is_system_app + else -> return null + } + return getText(id) + } + + override fun updateFooter(fp: FooterPreference) { + fp.setTitle(R.string.aep_native_debug_footer) + } +} + +class AppDefaultNativeDebuggingPrefController(ctx: Context, key: String) : + BoolSettingFragmentPrefController(ctx, key, ExtSettings.ALLOW_NATIVE_DEBUG_BY_DEFAULT) { + + override fun getSummary(): CharSequence { + return resText(if (setting.get(mContext)) R.string.aep_default_summary_allowed_for_3p_apps else R.string.aep_default_summary_blocked) + } +} + +class AppDefaultNativeDebuggingFragment : BoolSettingFragment() { + + override fun getSetting(): BoolSetting { + invertSetting = true + return ExtSettings.ALLOW_NATIVE_DEBUG_BY_DEFAULT + } + + override fun getTitle() = getText(R.string.aep_native_debug_title) + + override fun getMainSwitchTitle() = getText(R.string.aep_default_main_switch_block_for_3p_apps) + + override fun addExtraPrefs(screen: PreferenceScreen) { + AswAdapterNativeDebugging.addAppListPageLink(screen) + } + + override fun makeFooterPref(builder: FooterPreference.Builder): FooterPreference { + val text = AppPrefUtils.getFooterForDefaultHardeningSetting( + requireContext(), + R.string.aep_native_debug_footer + ) + return builder.setTitle(text).build() + } +} + +class NativeDebuggingAppListPrefController(context: Context, preferenceKey: String) : + AswAppListPrefController(context, preferenceKey, AswAdapterNativeDebugging) { + + override fun getAvailabilityStatus() = ExtSettingControllerHelper + .getSecondaryUserOnlySettingAvailability(mContext) +} diff --git a/src/com/android/settings/core/gateway/SettingsGateway.java b/src/com/android/settings/core/gateway/SettingsGateway.java index fc5421a9ef7..b3c1ec08472 100644 --- a/src/com/android/settings/core/gateway/SettingsGateway.java +++ b/src/com/android/settings/core/gateway/SettingsGateway.java @@ -229,6 +229,7 @@ public class SettingsGateway { * security exception if the fragment it needs to display is not in this list. */ public static final String[] ENTRY_FRAGMENTS = { + com.android.settings.applications.AppNativeDebuggingFragment.class.getName(), com.android.settings.applications.AppHardenedMallocFragment.class.getName(), com.android.settings.safetycenter.ExploitProtectionFragment.class.getName(), AdvancedConnectedDeviceDashboardFragment.class.getName(), diff --git a/src/com/android/settings/spa/SettingsSpaEnvironment.kt b/src/com/android/settings/spa/SettingsSpaEnvironment.kt index 7d3e08323c9..9ca0a5c46c9 100644 --- a/src/com/android/settings/spa/SettingsSpaEnvironment.kt +++ b/src/com/android/settings/spa/SettingsSpaEnvironment.kt @@ -103,6 +103,7 @@ open class SettingsSpaEnvironment(context: Context) : SpaEnvironment(context) { AppsMainPageProvider, com.android.settings.applications.AswAdapterUseHardenedMalloc.makeAppListPageProvider(), com.android.settings.applications.AswAdapterUseExtendedVaSpace.makeAppListPageProvider(), + com.android.settings.applications.AswAdapterNativeDebugging.makeAppListPageProvider(), AllAppListPageProvider, AppInfoSettingsProvider, SpecialAppAccessPageProvider, diff --git a/src/com/android/settings/spa/app/appinfo/AppInfoSettings.kt b/src/com/android/settings/spa/app/appinfo/AppInfoSettings.kt index 1cf0ce258d1..10df60fcf93 100644 --- a/src/com/android/settings/spa/app/appinfo/AppInfoSettings.kt +++ b/src/com/android/settings/spa/app/appinfo/AppInfoSettings.kt @@ -185,6 +185,7 @@ private fun AppInfoSettings(packageInfoPresenter: PackageInfoPresenter) { AppExploitProtectionCompatModeSwitchPreference(app, packageInfoPresenter) com.android.settings.applications.AppHardenedMallocPreference(app) com.android.settings.applications.AppExtendedVaSpacePreference(app) + com.android.settings.applications.AppNativeDebuggingPreference(app) } Category(title = stringResource(R.string.app_install_details_group_title)) { From bb89e6aec911a0601af6773b452e497a56049093 Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Fri, 30 Aug 2024 16:25:59 +0300 Subject: [PATCH 062/162] add per-app setting for memory tagging --- AndroidManifest.xml | 16 +++ res/values/strings_app_exploit_protection.xml | 18 +++ res/xml/exploit_protection_settings.xml | 11 ++ src/com/android/settings/Settings.java | 2 + .../settings/applications/AppMemoryTagging.kt | 111 ++++++++++++++++++ .../core/gateway/SettingsGateway.java | 1 + .../settings/spa/SettingsSpaEnvironment.kt | 1 + .../spa/app/appinfo/AppInfoSettings.kt | 1 + 8 files changed, 161 insertions(+) create mode 100644 src/com/android/settings/applications/AppMemoryTagging.kt diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 369ce4b1002..99b51175c30 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -6058,6 +6058,22 @@ android:value="@string/menu_key_apps"/> + + + + + + + + + + + Native debugging is always blocked for preinstalled apps + Memory tagging + Show notifications about detected errors + Memory tagging provides strong protections against exploitation of heap memory bugs (e.g. use-after-free, buffer overflow). + Memory tagging is always enabled for preinstalled apps + Memory tagging is always enabled for apps that don’t have native code + This app has opted-in to memory tagging + + Enable by default + + This setting doesn’t apply to apps that are known to be compatible with memory tagging + "Memory tagging provides strong protections against exploitation of heap memory bugs (e.g. use-after-free, buffer overflow). + +Memory tagging is always enabled for preinstalled apps and for third-party apps that are known to be +compatible with it (e.g. apps that don’t have native code), regardless of this setting." + Enabled by default + + Disabled by default, except for apps that are known to be compatible with memory tagging + diff --git a/res/xml/exploit_protection_settings.xml b/res/xml/exploit_protection_settings.xml index c56c38ef64c..d2ed9ca38c0 100644 --- a/res/xml/exploit_protection_settings.xml +++ b/res/xml/exploit_protection_settings.xml @@ -29,6 +29,17 @@ android:title="@string/aep_hmalloc" settings:controller="com.android.settings.applications.HardenedMallocAppListPrefController" /> + + + + () { + + override fun getAppSwitch() = AswUseMemoryTagging.I + + override fun getAswTitle(ctx: Context) = ctx.getText(R.string.aep_memtag) + + override fun getNotificationToggleTitle(ctx: Context) = ctx.getText(R.string.aep_memtag_notif_toggle_time) + + override fun getDetailFragmentClass() = AppMemtagFragment::class +} + +private val isMemoryTaggingSupported = Zygote.nativeSupportsMemoryTagging() + +@Composable +fun AppMemtagPreference(app: ApplicationInfo) { + if (!isMemoryTaggingSupported) { + return + } + + val context = LocalContext.current + AswPreference(context, app, AswAdapterUseMemoryTagging) +} + +class AppMemtagFragment : AswExploitProtectionFragment() { + + override fun getAswAdapter() = AswAdapterUseMemoryTagging + + override fun getSummaryForImmutabilityReason(ir: Int): CharSequence? { + val id = when (ir) { + AppSwitch.IR_IS_SYSTEM_APP -> R.string.aep_memtag_dvr_is_system_app + AppSwitch.IR_NO_NATIVE_CODE -> R.string.aep_memtag_dvr_no_native_code + AppSwitch.IR_OPTED_IN_VIA_MANIFEST -> R.string.aep_memtag_dvr_manifest_opt_in + else -> return null + } + return getText(id) + } + + override fun updateFooter(fp: FooterPreference) { + fp.setTitle(R.string.aep_memtag_footer) + } +} + +class AppDefaultMemtagPrefController(ctx: Context, key: String) : + BoolSettingFragmentPrefController(ctx, key, ExtSettings.FORCE_APP_MEMTAG_BY_DEFAULT) { + + private val isSupported = Zygote.nativeSupportsMemoryTagging() + + override fun getAvailabilityStatus(): Int { + if (!isSupported) { + return UNSUPPORTED_ON_DEVICE + } + + return super.getAvailabilityStatus() + } + + override fun getSummaryOn() = resText(R.string.aep_default_memtag_summary_on) + override fun getSummaryOff() = resText(R.string.aep_default_memtag_summary_off) +} + +class AppDefaultMemtagFragment : BoolSettingFragment() { + + override fun getSetting() = ExtSettings.FORCE_APP_MEMTAG_BY_DEFAULT + + override fun getTitle() = resText(R.string.aep_memtag) + + override fun getMainSwitchTitle() = resText(R.string.aep_default_memtag_main_switch_title) + override fun getMainSwitchSummary() = resText(R.string.aep_default_memtag_main_switch_summary) + + override fun addExtraPrefs(screen: PreferenceScreen) { + AswAdapterUseMemoryTagging.addAppListPageLink(screen) + } + + override fun makeFooterPref(builder: FooterPreference.Builder): FooterPreference { + val text = AppPrefUtils.getFooterForDefaultHardeningSetting(requireContext(), + R.string.aep_default_memtag_footer) + return builder.setTitle(text).build() + } +} + +class MemtagAppListPrefController(context: Context, preferenceKey: String) : + AswAppListPrefController(context, preferenceKey, AswAdapterUseMemoryTagging) { + + private val isSupported = Zygote.nativeSupportsMemoryTagging() + + override fun getAvailabilityStatus(): Int { + if (!isSupported) { + return UNSUPPORTED_ON_DEVICE + } + return ExtSettingControllerHelper + .getSecondaryUserOnlySettingAvailability(mContext) + } +} diff --git a/src/com/android/settings/core/gateway/SettingsGateway.java b/src/com/android/settings/core/gateway/SettingsGateway.java index b3c1ec08472..4a44ed3ce49 100644 --- a/src/com/android/settings/core/gateway/SettingsGateway.java +++ b/src/com/android/settings/core/gateway/SettingsGateway.java @@ -230,6 +230,7 @@ public class SettingsGateway { */ public static final String[] ENTRY_FRAGMENTS = { com.android.settings.applications.AppNativeDebuggingFragment.class.getName(), + com.android.settings.applications.AppMemtagFragment.class.getName(), com.android.settings.applications.AppHardenedMallocFragment.class.getName(), com.android.settings.safetycenter.ExploitProtectionFragment.class.getName(), AdvancedConnectedDeviceDashboardFragment.class.getName(), diff --git a/src/com/android/settings/spa/SettingsSpaEnvironment.kt b/src/com/android/settings/spa/SettingsSpaEnvironment.kt index 9ca0a5c46c9..4337c1f3725 100644 --- a/src/com/android/settings/spa/SettingsSpaEnvironment.kt +++ b/src/com/android/settings/spa/SettingsSpaEnvironment.kt @@ -102,6 +102,7 @@ open class SettingsSpaEnvironment(context: Context) : SpaEnvironment(context) { HomePageProvider, AppsMainPageProvider, com.android.settings.applications.AswAdapterUseHardenedMalloc.makeAppListPageProvider(), + com.android.settings.applications.AswAdapterUseMemoryTagging.makeAppListPageProvider(), com.android.settings.applications.AswAdapterUseExtendedVaSpace.makeAppListPageProvider(), com.android.settings.applications.AswAdapterNativeDebugging.makeAppListPageProvider(), AllAppListPageProvider, diff --git a/src/com/android/settings/spa/app/appinfo/AppInfoSettings.kt b/src/com/android/settings/spa/app/appinfo/AppInfoSettings.kt index 10df60fcf93..398a6de5b08 100644 --- a/src/com/android/settings/spa/app/appinfo/AppInfoSettings.kt +++ b/src/com/android/settings/spa/app/appinfo/AppInfoSettings.kt @@ -184,6 +184,7 @@ private fun AppInfoSettings(packageInfoPresenter: PackageInfoPresenter) { Category(title = stringResource(R.string.exploit_protection_category_title)) { AppExploitProtectionCompatModeSwitchPreference(app, packageInfoPresenter) com.android.settings.applications.AppHardenedMallocPreference(app) + com.android.settings.applications.AppMemtagPreference(app) com.android.settings.applications.AppExtendedVaSpacePreference(app) com.android.settings.applications.AppNativeDebuggingPreference(app) } From f4470ecc52871cf7e3edd9f12bbcfe920ef715a1 Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Mon, 27 Nov 2023 21:47:26 +0200 Subject: [PATCH 063/162] add toggle for system process crash notifications --- res/values/strings_ext.xml | 3 +++ res/xml/more_security_privacy_settings.xml | 8 ++++++++ 2 files changed, 11 insertions(+) diff --git a/res/values/strings_ext.xml b/res/values/strings_ext.xml index 219e9dfd244..cecf804a5ce 100644 --- a/res/values/strings_ext.xml +++ b/res/values/strings_ext.xml @@ -137,4 +137,7 @@ There are HTTP, HTTPS, DNS, DNS-over-TLS and DNS-over-HTTPS connectivity checks. Charge other devices by placing them on the back of your phone Battery share + + Notify about system process crashes + Such crashes may indicate exploitation attempts diff --git a/res/xml/more_security_privacy_settings.xml b/res/xml/more_security_privacy_settings.xml index 025f1c20755..69b209fa4a6 100644 --- a/res/xml/more_security_privacy_settings.xml +++ b/res/xml/more_security_privacy_settings.xml @@ -235,6 +235,14 @@ settings:keywords="@string/keywords_app_pinning" settings:controller="com.android.settings.security.ScreenPinningPreferenceController" /> + + Date: Fri, 29 Sep 2023 16:16:00 +0300 Subject: [PATCH 064/162] Widevine provisioning setting Signed-off-by: maade69 <70593890+maade69@users.noreply.github.com> --- res/values/strings_ext.xml | 5 +++ res/xml/network_provider_internet.xml | 6 +++ .../WidevineProvisioningPrefController.java | 43 +++++++++++++++++++ 3 files changed, 54 insertions(+) create mode 100644 src/com/android/settings/network/WidevineProvisioningPrefController.java diff --git a/res/values/strings_ext.xml b/res/values/strings_ext.xml index cecf804a5ce..c0ac38edb83 100644 --- a/res/values/strings_ext.xml +++ b/res/values/strings_ext.xml @@ -111,6 +111,11 @@ There are HTTP, HTTPS, DNS, DNS-over-TLS and DNS-over-HTTPS connectivity checks. Use secure app spawning Launch apps in a more secure way than Android which takes slightly longer and increases memory usage by app processes. + Widevine provisioning + GrapheneOS proxy + Google server + The provisioned certificate will be used for accessing DRM protected content. + App installs and updates diff --git a/res/xml/network_provider_internet.xml b/res/xml/network_provider_internet.xml index b4becf7c709..594d307f83e 100644 --- a/res/xml/network_provider_internet.xml +++ b/res/xml/network_provider_internet.xml @@ -138,4 +138,10 @@ android:title="@string/remote_provisioning_title" android:order="35" settings:controller="com.android.settings.network.RemoteProvisioningPrefController" /> + + diff --git a/src/com/android/settings/network/WidevineProvisioningPrefController.java b/src/com/android/settings/network/WidevineProvisioningPrefController.java new file mode 100644 index 00000000000..09d62f012ac --- /dev/null +++ b/src/com/android/settings/network/WidevineProvisioningPrefController.java @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.network; + +import android.content.Context; +import android.ext.settings.WidevineProvisioningSettings; + +import com.android.settings.R; +import androidx.preference.PreferenceScreen; +import com.android.settings.ext.IntSettingPrefController; +import com.android.settings.ext.RadioButtonPickerFragment2; + +public class WidevineProvisioningPrefController extends IntSettingPrefController { + + public WidevineProvisioningPrefController(Context ctx, String key) { + super(ctx, key, WidevineProvisioningSettings.SERVER_SETTING); + } + + @Override + public void addPrefsAfterList(RadioButtonPickerFragment2 fragment, PreferenceScreen screen) { + addFooterPreference(screen, R.string.widevine_provisioning_footer); + } + + @Override + protected void getEntries(Entries entries) { + entries.add(R.string.widevine_provisioning_enabled_grapheneos_proxy, WidevineProvisioningSettings.WV_GRAPHENEOS_PROXY); + entries.add(R.string.widevine_provisioning_enabled_google_server, WidevineProvisioningSettings.WV_STANDARD_SERVER); + } +} From 723df5723893f84f65ac4c3be9a04289118b7a48 Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Mon, 18 Dec 2023 15:38:16 +0200 Subject: [PATCH 065/162] remove confusing mention of Android Auto from "Connected devices" screen --- .../AdvancedConnectedDeviceController.java | 10 +------- ...AdvancedConnectedDeviceControllerTest.java | 25 ------------------- 2 files changed, 1 insertion(+), 34 deletions(-) diff --git a/src/com/android/settings/connecteddevice/AdvancedConnectedDeviceController.java b/src/com/android/settings/connecteddevice/AdvancedConnectedDeviceController.java index 2b86a2ad048..57215f11486 100644 --- a/src/com/android/settings/connecteddevice/AdvancedConnectedDeviceController.java +++ b/src/com/android/settings/connecteddevice/AdvancedConnectedDeviceController.java @@ -35,7 +35,6 @@ public class AdvancedConnectedDeviceController extends BasePreferenceController private static final String DRIVING_MODE_SETTINGS_ENABLED = "gearhead:driving_mode_settings_enabled"; - private static final String GEARHEAD_PACKAGE = "com.google.android.projection.gearhead"; public AdvancedConnectedDeviceController(Context context, String preferenceKey) { super(context, preferenceKey); @@ -60,7 +59,7 @@ public static int getConnectedDevicesSummaryResourceId(Context context) { new NfcPreferenceController(context, NfcPreferenceController.KEY_TOGGLE_NFC); return getConnectedDevicesSummaryResourceId(nfcPreferenceController, - isDrivingModeAvailable(context), isAndroidAutoSettingAvailable(context)); + isDrivingModeAvailable(context), false); } @VisibleForTesting @@ -69,13 +68,6 @@ static boolean isDrivingModeAvailable(Context context) { getInt(context.getContentResolver(), DRIVING_MODE_SETTINGS_ENABLED, 0) == 1; } - @VisibleForTesting - static boolean isAndroidAutoSettingAvailable(Context context) { - final Intent intent = new Intent(IA_SETTINGS_ACTION); - intent.setPackage(GEARHEAD_PACKAGE); - return intent.resolveActivity(context.getPackageManager()) != null; - } - @VisibleForTesting static int getConnectedDevicesSummaryResourceId(NfcPreferenceController nfcPreferenceController, diff --git a/tests/robotests/src/com/android/settings/connecteddevice/AdvancedConnectedDeviceControllerTest.java b/tests/robotests/src/com/android/settings/connecteddevice/AdvancedConnectedDeviceControllerTest.java index 6ae670dc120..2af9242dab8 100644 --- a/tests/robotests/src/com/android/settings/connecteddevice/AdvancedConnectedDeviceControllerTest.java +++ b/tests/robotests/src/com/android/settings/connecteddevice/AdvancedConnectedDeviceControllerTest.java @@ -99,31 +99,6 @@ public void isDrivingModeAvailable_returnFalse() { AdvancedConnectedDeviceController.isDrivingModeAvailable(mContext)).isFalse(); } - @Test - public void isAndroidAutoSettingAvailable_returnTrue() { - final ApplicationInfo appInfo = - ApplicationInfoBuilder.newBuilder().setPackageName(ANDROID_AUTO_PACKAGE).build(); - final ActivityInfo activityInfo = new ActivityInfo(); - activityInfo.packageName = ANDROID_AUTO_PACKAGE; - activityInfo.name = ANDROID_AUTO_PACKAGE; - activityInfo.applicationInfo = appInfo; - final ResolveInfo resolveInfo = new ResolveInfo(); - resolveInfo.activityInfo = activityInfo; - mShadowPackageManager.addResolveInfoForIntent( - buildAndroidAutoSettingsIntent(), - resolveInfo); - - assertThat( - AdvancedConnectedDeviceController.isAndroidAutoSettingAvailable(mContext)).isTrue(); - } - - @Test - public void isAndroidAutoSettingAvailable_returnFalse() { - // No ResolveInfo for Android Auto, expect false. - assertThat( - AdvancedConnectedDeviceController.isAndroidAutoSettingAvailable(mContext)).isFalse(); - } - @Test public void getConnectedDevicesSummaryResourceId_NFCAndDrivingModeAvailable() { // NFC available, driving mode available From a2cb5c35dc1be859bf895f47312ab4a851a88760 Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Sat, 6 Jan 2024 19:37:47 +0200 Subject: [PATCH 066/162] add logcat viewer link to System settings --- AndroidManifest.xml | 1 + res/values/strings_ext.xml | 3 ++ res/xml/system_dashboard_fragment.xml | 7 ++++ .../system/LogcatLinkPrefController.java | 34 +++++++++++++++++++ 4 files changed, 45 insertions(+) create mode 100644 src/com/android/settings/system/LogcatLinkPrefController.java diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 99b51175c30..c1fa945db61 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -150,6 +150,7 @@ + Notify about system process crashes Such crashes may indicate exploitation attempts + + View logs + diff --git a/res/xml/system_dashboard_fragment.xml b/res/xml/system_dashboard_fragment.xml index 2bef02855dc..704dac9f385 100644 --- a/res/xml/system_dashboard_fragment.xml +++ b/res/xml/system_dashboard_fragment.xml @@ -113,6 +113,13 @@ + + Date: Sat, 2 Mar 2024 11:25:46 +0200 Subject: [PATCH 067/162] add logcat viewer link to App info screen --- .../spa/app/appinfo/AppInfoSettings.kt | 1 + .../spa/app/appinfo/AppLogcatPreference.kt | 29 +++++++++++++++++++ 2 files changed, 30 insertions(+) create mode 100644 src/com/android/settings/spa/app/appinfo/AppLogcatPreference.kt diff --git a/src/com/android/settings/spa/app/appinfo/AppInfoSettings.kt b/src/com/android/settings/spa/app/appinfo/AppInfoSettings.kt index 398a6de5b08..83979d639f5 100644 --- a/src/com/android/settings/spa/app/appinfo/AppInfoSettings.kt +++ b/src/com/android/settings/spa/app/appinfo/AppInfoSettings.kt @@ -162,6 +162,7 @@ private fun AppInfoSettings(packageInfoPresenter: PackageInfoPresenter) { AppLocalePreference(app) AppOpenByDefaultPreference(app) DefaultAppShortcuts(app) + AppLogcatPreference(app) } Category(title = stringResource(R.string.unused_apps_category)) { diff --git a/src/com/android/settings/spa/app/appinfo/AppLogcatPreference.kt b/src/com/android/settings/spa/app/appinfo/AppLogcatPreference.kt new file mode 100644 index 00000000000..14e3c60b5e1 --- /dev/null +++ b/src/com/android/settings/spa/app/appinfo/AppLogcatPreference.kt @@ -0,0 +1,29 @@ +package com.android.settings.spa.app.appinfo + +import android.content.pm.ApplicationInfo +import android.ext.LogViewerApp +import androidx.compose.runtime.Composable +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.stringResource +import com.android.settings.R +import com.android.settingslib.spa.widget.preference.Preference +import com.android.settingslib.spa.widget.preference.PreferenceModel +import com.android.settingslib.spaprivileged.model.app.installed +import com.android.settingslib.spaprivileged.model.app.userHandle + +@Composable +fun AppLogcatPreference(app: ApplicationInfo) { + if (!app.installed) { + return + } + + val context = LocalContext.current + + Preference(object : PreferenceModel { + override val title = stringResource(R.string.view_logs) + override val onClick = { + val intent = LogViewerApp.getPackageLogcatIntent(app.packageName) + context.startActivityAsUser(intent, app.userHandle) + } + }) +} From 5efbc38ef7e6186909391d811ebd232ff53e65bb Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Wed, 21 Feb 2024 16:39:26 +0200 Subject: [PATCH 068/162] add USB-C port and pogo pins security setting --- res/values/strings_ext.xml | 32 +++++++ res/xml/exploit_protection_settings.xml | 10 +++ .../UsbPortSecurityPrefController.java | 85 +++++++++++++++++++ 3 files changed, 127 insertions(+) create mode 100644 src/com/android/settings/security/UsbPortSecurityPrefController.java diff --git a/res/values/strings_ext.xml b/res/values/strings_ext.xml index 2f3c8d88604..4847d62aa03 100644 --- a/res/values/strings_ext.xml +++ b/res/values/strings_ext.xml @@ -148,4 +148,36 @@ There are HTTP, HTTPS, DNS, DNS-over-TLS and DNS-over-HTTPS connectivity checks. View logs + USB-C port + Off + Turns off the USB-C port. + Doesn’t impact the separate charging mode, which is activated by turning off the device and plugging it in to a charger. + + Charging-only + Turns off all non-charging USB-C port functionality. + Charging-only when locked + Enables the charging-only mode when the + device is locked and disables it when the device becomes unlocked. If the port is already + plugged-in at the time when the device becomes locked, then the activation of charging-only + mode will be delayed until the port is disconnected. + Charging-only when locked, except before first unlock + This mode has the same behavior + as the “%1$s” mode, except for an additional exemption for before-first-unlock connections. + + On + Does not add any restrictions. + + USB-C port and pogo pins + USB-C port off, pogo pins used only for charging + Turns off the USB-C port and turns off all + non-charging pogo pins functionality. Doesn’t impact the separate charging mode, which is + activated by turning off the device and plugging it in to a charger. + + Turns off all non-charging USB-C port and pogo pins functionality. + Enables the charging-only mode when the + device is locked and disables it when the device becomes unlocked. If the port is already + plugged-in at the time when the device becomes locked, then the activation of charging-only + mode will be delayed until the port is disconnected. The same behavior applies to pogo pins. + + diff --git a/res/xml/exploit_protection_settings.xml b/res/xml/exploit_protection_settings.xml index d2ed9ca38c0..530e97cd956 100644 --- a/res/xml/exploit_protection_settings.xml +++ b/res/xml/exploit_protection_settings.xml @@ -10,6 +10,16 @@ android:title="@string/auto_reboot_title" settings:controller="com.android.settings.security.AutoRebootPrefController" /> + + + + Date: Thu, 7 Mar 2024 12:21:53 +0200 Subject: [PATCH 069/162] enable "About phone -> Battery information" screen Squashed with: commit 50f8f1d6d2c588e8e5504f6f9f6c071c6b26938f Author: Daniel Micay Date: Sat Mar 9 10:06:21 2024 -0500 use 2021-01-01 as minimum battery date --- .../fuelgauge/BatterySettingsFeatureProviderImpl.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/com/android/settings/fuelgauge/BatterySettingsFeatureProviderImpl.java b/src/com/android/settings/fuelgauge/BatterySettingsFeatureProviderImpl.java index 19c10d78306..d2b9c0cebb1 100644 --- a/src/com/android/settings/fuelgauge/BatterySettingsFeatureProviderImpl.java +++ b/src/com/android/settings/fuelgauge/BatterySettingsFeatureProviderImpl.java @@ -32,17 +32,17 @@ public class BatterySettingsFeatureProviderImpl implements BatterySettingsFeatur @Override public boolean isManufactureDateAvailable(Context context, long manufactureDateMs) { - return false; + return manufactureDateMs > 1_609_459_200_000L; // 2021-01-01 } @Override public boolean isFirstUseDateAvailable(Context context, long firstUseDateMs) { - return false; + return firstUseDateMs > 1_609_459_200_000L; // 2021-01-01 } @Override public boolean isBatteryInfoEnabled(Context context) { - return false; + return true; } @Override From 52d5942ea7e98cebae52038a930595822babafe4 Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Sun, 17 Mar 2024 17:40:23 +0200 Subject: [PATCH 070/162] fix footer formatting issue on App pinning screen Since 20976c3a53802a8b78cab20e49154244ddaf9ddd screen_pinning_description is a formatted string, it can't be used directly from XML. --- res/xml/screen_pinning_settings.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/res/xml/screen_pinning_settings.xml b/res/xml/screen_pinning_settings.xml index 2c4402da89e..f06b42ceab1 100644 --- a/res/xml/screen_pinning_settings.xml +++ b/res/xml/screen_pinning_settings.xml @@ -30,7 +30,6 @@ From 95ec88d7c2f8dc42b9f7d80226c63ffc5d559961 Mon Sep 17 00:00:00 2001 From: Jitesh Singh Date: Tue, 30 Jan 2024 19:48:12 +0530 Subject: [PATCH 071/162] fixes redundant horizontal margin issue on tablets --- res/values-sw600dp-v31/dimens.xml | 9 +++++++++ res/values-sw600dp/dimens.xml | 8 ++++++++ 2 files changed, 17 insertions(+) create mode 100644 res/values-sw600dp-v31/dimens.xml diff --git a/res/values-sw600dp-v31/dimens.xml b/res/values-sw600dp-v31/dimens.xml new file mode 100644 index 00000000000..3542f62dc08 --- /dev/null +++ b/res/values-sw600dp-v31/dimens.xml @@ -0,0 +1,9 @@ + + + 24dp + 24dp + 8dp + 20dp + 20dp + 8dp + diff --git a/res/values-sw600dp/dimens.xml b/res/values-sw600dp/dimens.xml index f5615bfbe67..255df2876d9 100755 --- a/res/values-sw600dp/dimens.xml +++ b/res/values-sw600dp/dimens.xml @@ -29,6 +29,14 @@ 348dp + + 24dp + 24dp + 8dp + 20dp + 20dp + 8dp + 104dp 448dp From 456c7563708379c2839a9455e44cff571b04cdce Mon Sep 17 00:00:00 2001 From: Jitesh Singh Date: Wed, 31 Jan 2024 01:41:53 +0530 Subject: [PATCH 072/162] internet setup activity Co-authored-by: Dmitry Muhomor Co-authored-by: quh4gko8 <88831734+quh4gko8@users.noreply.github.com> --- AndroidManifest.xml | 13 ++ res/drawable/baseline_wifi.xml | 10 ++ res/drawable/baseline_wifi_glif.xml | 7 + res/layout/settings_main_prefs.xml | 62 ++++--- res/values/dimens.xml | 5 + res/values/themes_suw.xml | 2 + .../network/InternetSetupActivity.java | 52 ++++++ .../network/NetworkProviderSettings.java | 4 +- .../network/NetworkProviderSetup.java | 155 ++++++++++++++++++ 9 files changed, 276 insertions(+), 34 deletions(-) create mode 100644 res/drawable/baseline_wifi.xml create mode 100644 res/drawable/baseline_wifi_glif.xml create mode 100644 src/com/android/settings/network/InternetSetupActivity.java create mode 100644 src/com/android/settings/network/NetworkProviderSetup.java diff --git a/AndroidManifest.xml b/AndroidManifest.xml index c1fa945db61..6cce54f67f3 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -520,6 +520,19 @@ android:value="true" /> + + + + + + + + + + + diff --git a/res/drawable/baseline_wifi_glif.xml b/res/drawable/baseline_wifi_glif.xml new file mode 100644 index 00000000000..3f12842b089 --- /dev/null +++ b/res/drawable/baseline_wifi_glif.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/res/layout/settings_main_prefs.xml b/res/layout/settings_main_prefs.xml index 48352e2efa0..5111332bfbe 100644 --- a/res/layout/settings_main_prefs.xml +++ b/res/layout/settings_main_prefs.xml @@ -34,40 +34,38 @@ android:layout_height="0dp" android:layout_weight="1"/> - - -