From ac3ba8da4188db7f6e2a10714ffcda67eb6fd319 Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Fri, 15 Nov 2024 08:18:09 +0200 Subject: [PATCH 001/112] add isLoggable check to overly verbose PrefCtrlListHelper log statement --- .../android/settings/core/PreferenceControllerListHelper.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/com/android/settings/core/PreferenceControllerListHelper.java b/src/com/android/settings/core/PreferenceControllerListHelper.java index dea8c971c49..9dc0a9fa108 100644 --- a/src/com/android/settings/core/PreferenceControllerListHelper.java +++ b/src/com/android/settings/core/PreferenceControllerListHelper.java @@ -74,7 +74,9 @@ public static List getPreferenceControllersFromXml(Con try { controller = BasePreferenceController.createInstance(context, controllerName); } catch (IllegalStateException e) { - Log.d(TAG, "Could not find Context-only controller for pref: " + controllerName); + if (Log.isLoggable(TAG, Log.DEBUG)) { + Log.d(TAG, "Could not find Context-only controller for pref: " + controllerName); + } final String key = metadata.getString(METADATA_KEY); final boolean isWorkProfile = metadata.getBoolean(METADATA_FOR_WORK, false); if (TextUtils.isEmpty(key)) { From 8fb4d8e254d2f0118bca9e522c05f0f570fddad1 Mon Sep 17 00:00:00 2001 From: flawedworld Date: Sat, 5 Feb 2022 17:42:07 +0000 Subject: [PATCH 002/112] add GrapheneOS icon --- AndroidManifest.xml | 3 ++- res/drawable/ic_launcher_foreground.xml | 30 +++++++++++++++++++++++++ res/mipmap-anydpi/ic_launcher.xml | 6 +++++ res/mipmap-anydpi/ic_launcher_round.xml | 6 +++++ res/values/ic_launcher_background.xml | 4 ++++ 5 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 res/drawable/ic_launcher_foreground.xml create mode 100644 res/mipmap-anydpi/ic_launcher.xml create mode 100644 res/mipmap-anydpi/ic_launcher_round.xml create mode 100644 res/values/ic_launcher_background.xml diff --git a/AndroidManifest.xml b/AndroidManifest.xml index cc4d898403a..ffdd7c23dcb 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -152,7 +152,8 @@ + + + + + diff --git a/res/mipmap-anydpi/ic_launcher.xml b/res/mipmap-anydpi/ic_launcher.xml new file mode 100644 index 00000000000..5c84730caa7 --- /dev/null +++ b/res/mipmap-anydpi/ic_launcher.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/res/mipmap-anydpi/ic_launcher_round.xml b/res/mipmap-anydpi/ic_launcher_round.xml new file mode 100644 index 00000000000..5c84730caa7 --- /dev/null +++ b/res/mipmap-anydpi/ic_launcher_round.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/res/values/ic_launcher_background.xml b/res/values/ic_launcher_background.xml new file mode 100644 index 00000000000..f42ada656ee --- /dev/null +++ b/res/values/ic_launcher_background.xml @@ -0,0 +1,4 @@ + + + #FFFFFF + From 23c8ad673eedf0146e46d721a6b7af5f56cbe500 Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Fri, 14 Oct 2022 21:08:02 -0400 Subject: [PATCH 003/112] set styles/wallpaper picker action name --- res/values/config.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/res/values/config.xml b/res/values/config.xml index 065d28a786b..7967d840ee5 100644 --- a/res/values/config.xml +++ b/res/values/config.xml @@ -53,9 +53,9 @@ - + android.intent.action.MAIN - + android.intent.action.MAIN com.android.wallpaper.LAUNCH_SOURCE From b060135fabf0c07d067d18a1ad9ca38949073f78 Mon Sep 17 00:00:00 2001 From: Danny Lin Date: Sat, 17 Apr 2021 15:15:51 +0100 Subject: [PATCH 004/112] Settings: Integrate ThemePicker and WallpaperPicker2 This uses the standalone wallpaper picker class from WallpaperPicker2 as seen in the Pixel stock ROM. --- res/values/config.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/res/values/config.xml b/res/values/config.xml index 7967d840ee5..25f4db8c53d 100644 --- a/res/values/config.xml +++ b/res/values/config.xml @@ -48,10 +48,10 @@ - com.android.settings - com.android.settings.Settings$WallpaperSettingsActivity + com.android.wallpaper + com.android.wallpaper.picker.CategoryPickerActivity - + com.android.customization.picker.CustomizationPickerActivity android.intent.action.MAIN From c2bf569ccfe971654663112a76b005294eb299a6 Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Tue, 16 Feb 2021 02:22:41 -0500 Subject: [PATCH 005/112] disable showing wallpaper attribution --- 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 25f4db8c53d..dadd149b7fd 100644 --- a/res/values/config.xml +++ b/res/values/config.xml @@ -478,7 +478,7 @@ true - true + false true From cb4c7cd6b1f539387547281f559c619976561ca2 Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Wed, 10 Mar 2021 00:45:12 -0500 Subject: [PATCH 006/112] add TalkBack accessibility service --- res/values/config.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/res/values/config.xml b/res/values/config.xml index dadd149b7fd..153dbce2c86 100644 --- a/res/values/config.xml +++ b/res/values/config.xml @@ -81,6 +81,7 @@ com.example.package.first/com.example.class.FirstService com.example.package.second/com.example.class.SecondService --> + com.android.talkback/com.google.android.marvin.talkback.TalkBackService From 5d309c42a7e36e83519ffcfcaabc6d348bfc9a61 Mon Sep 17 00:00:00 2001 From: inthewaves Date: Sun, 20 Sep 2020 17:57:30 -0700 Subject: [PATCH 007/112] get outer NFC preference to listen for changes The NFC preference in Settings -> Connected devices -> Connection preferences doesn't listen to changes from the NFC tile. (This wasn't an issue in Android 10, because there used to be a SwitchPreference that listened there.) --- .../NfcAndPaymentFragmentController.java | 59 ++++++++++++++++++- 1 file changed, 58 insertions(+), 1 deletion(-) diff --git a/src/com/android/settings/connecteddevice/NfcAndPaymentFragmentController.java b/src/com/android/settings/connecteddevice/NfcAndPaymentFragmentController.java index ee0021ec951..f16dd378db5 100644 --- a/src/com/android/settings/connecteddevice/NfcAndPaymentFragmentController.java +++ b/src/com/android/settings/connecteddevice/NfcAndPaymentFragmentController.java @@ -16,21 +16,47 @@ package com.android.settings.connecteddevice; +import android.content.BroadcastReceiver; import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; import android.content.pm.PackageManager; import android.nfc.NfcAdapter; import android.os.UserManager; +import androidx.preference.Preference; +import androidx.preference.PreferenceScreen; + import com.android.settings.R; import com.android.settings.core.BasePreferenceController; +import com.android.settingslib.core.lifecycle.LifecycleObserver; +import com.android.settingslib.core.lifecycle.events.OnResume; +import com.android.settingslib.core.lifecycle.events.OnStop; /** * Controller that used to show NFC and payment features */ -public class NfcAndPaymentFragmentController extends BasePreferenceController { +public class NfcAndPaymentFragmentController extends BasePreferenceController + implements LifecycleObserver, OnResume, OnStop { private final NfcAdapter mNfcAdapter; private final PackageManager mPackageManager; private final UserManager mUserManager; + private final IntentFilter mIntentFilter; + private Preference mPreference; + + private final BroadcastReceiver mReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (mPreference == null) { + return; + } + + final String action = intent.getAction(); + if (NfcAdapter.ACTION_ADAPTER_STATE_CHANGED.equals(action)) { + refreshSummary(mPreference); + } + } + }; public NfcAndPaymentFragmentController(Context context, String preferenceKey) { super(context, preferenceKey); @@ -38,6 +64,15 @@ public NfcAndPaymentFragmentController(Context context, String preferenceKey) { mPackageManager = context.getPackageManager(); mUserManager = context.getSystemService(UserManager.class); mNfcAdapter = NfcAdapter.getDefaultAdapter(context); + + mIntentFilter = isNfcAvailable() + ? new IntentFilter(NfcAdapter.ACTION_ADAPTER_STATE_CHANGED) : null; + } + + @Override + public void displayPreference(PreferenceScreen screen) { + super.displayPreference(screen); + mPreference = screen.findPreference(getPreferenceKey()); } @Override @@ -61,4 +96,26 @@ public CharSequence getSummary() { } return null; } + + @Override + public void onStop() { + if (!isNfcAvailable()) { + return; + } + + mContext.unregisterReceiver(mReceiver); + } + + @Override + public void onResume() { + if (!isNfcAvailable()) { + return; + } + + mContext.registerReceiver(mReceiver, mIntentFilter); + } + + private boolean isNfcAvailable() { + return mNfcAdapter != null; + } } From 3f182bccd1f6f27ba0be89a53c3cb1d54ee05b27 Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Tue, 8 Oct 2019 08:11:55 -0400 Subject: [PATCH 008/112] disable legacy suggestions --- 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 153dbce2c86..23ce3017d9a 100644 --- a/res/values/config.xml +++ b/res/values/config.xml @@ -240,7 +240,7 @@ Whether or not the homepage should be powered by legacy suggestion (versus contextual cards) Default to true as not all devices support contextual cards. --> - true + false false From 7ce844b2b1c797b899abd691f9cfd259de72311b Mon Sep 17 00:00:00 2001 From: Renlord Date: Sat, 11 Apr 2020 20:04:51 +1000 Subject: [PATCH 009/112] add missing android title for top_level_settings --- res/xml/top_level_settings.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/res/xml/top_level_settings.xml b/res/xml/top_level_settings.xml index 44fe7fcc3d3..fbbe0b28814 100644 --- a/res/xml/top_level_settings.xml +++ b/res/xml/top_level_settings.xml @@ -18,7 +18,8 @@ + android:key="top_level_settings" + android:title="Settings"> Date: Sun, 16 May 2021 00:51:15 +0100 Subject: [PATCH 010/112] 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 011/112] extend list of system apps that are not allowed to be disabled --- .../ApplicationFeatureProviderImpl.java | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/src/com/android/settings/applications/ApplicationFeatureProviderImpl.java b/src/com/android/settings/applications/ApplicationFeatureProviderImpl.java index 851d763ea94..9b8de55caf3 100644 --- a/src/com/android/settings/applications/ApplicationFeatureProviderImpl.java +++ b/src/com/android/settings/applications/ApplicationFeatureProviderImpl.java @@ -24,12 +24,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; @@ -205,6 +207,39 @@ 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, + }); + + 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 f2ef0e0285cf49c282d1dde9c064473919c58a93 Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Sun, 12 Feb 2023 20:21:09 +0200 Subject: [PATCH 012/112] 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 41887f47fe9ecc5bed8bae54d587a630dc5ed7b1 Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Thu, 6 Apr 2023 12:06:11 +0300 Subject: [PATCH 013/112] 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 5693ab4c7cc293b59f3e60f0af27c2f3b46e7497 Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Sun, 12 Feb 2023 19:43:44 +0200 Subject: [PATCH 014/112] add base class for ListPreference controllers --- .../ext/AbstractListPreferenceController.java | 242 ++++++++++++++++++ .../ext/RadioButtonPickerFragment2.java | 208 +++++++++++++++ .../widget/RadioButtonPickerFragment.java | 16 +- 3 files changed, 462 insertions(+), 4 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 d68a91afca8..547f2779ebc 100644 --- a/src/com/android/settings/widget/RadioButtonPickerFragment.java +++ b/src/com/android/settings/widget/RadioButtonPickerFragment.java @@ -55,7 +55,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"; @VisibleForTesting boolean mAppendStaticPreferences = false; @@ -166,6 +166,12 @@ protected SelectorWithWidgetPreference createPreference() { return new SelectorWithWidgetPreference(getPrefContext()); } + protected void addPrefsBeforeList(PreferenceScreen screen) { + if (!mAppendStaticPreferences) { + addStaticPreferences(screen); + } + } + public void updateCandidates() { mCandidates.clear(); final List candidateList = getCandidates(); @@ -181,9 +187,7 @@ public void updateCandidates() { if (mIllustrationId != 0) { addIllustration(screen); } - if (!mAppendStaticPreferences) { - addStaticPreferences(screen); - } + addPrefsBeforeList(screen); final int customLayoutResId = getRadioButtonPreferenceCustomLayoutResId(); if (shouldShowItemNone()) { @@ -210,6 +214,10 @@ public void updateCandidates() { } } mayCheckOnlyRadioButton(); + addPrefsAfterList(screen); + } + + protected void addPrefsAfterList(PreferenceScreen screen) { if (mAppendStaticPreferences) { addStaticPreferences(screen); } From abf37cc8df881a482ec5dcccd9de31199b5c53cc Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Tue, 14 Feb 2023 08:45:56 +0200 Subject: [PATCH 015/112] 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 e774390633e24baf6448e0b776260b8f9cabbe2b Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Sun, 12 Feb 2023 19:44:07 +0200 Subject: [PATCH 016/112] 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 | 14 ++- .../ext/BoolSettingPrefController.java | 90 +++++++++++++++++++ .../ext/ExtSettingControllerHelper.java | 72 +++++++++++++++ .../ext/ExtSettingPrefController.java | 12 +++ .../ext/IntSettingPrefController.java | 57 ++++++++++++ 7 files changed, 249 insertions(+), 1 deletion(-) 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 200253acce6..d404f3ebfb0 100644 --- a/res/values/attrs.xml +++ b/res/values/attrs.xml @@ -68,6 +68,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 df3cd922752..478a79e74e6 100644 --- a/src/com/android/settings/core/PreferenceXmlParserUtils.java +++ b/src/com/android/settings/core/PreferenceXmlParserUtils.java @@ -64,6 +64,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, @@ -91,11 +92,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"; @@ -162,6 +166,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)); } @@ -230,6 +238,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); } @@ -269,4 +281,4 @@ private static String getUserRestriction(Context context, AttributeSet attrs) { preferenceAttributes.recycle(); return userRestriction; } -} \ No newline at end of file +} diff --git a/src/com/android/settings/ext/BoolSettingPrefController.java b/src/com/android/settings/ext/BoolSettingPrefController.java new file mode 100644 index 00000000000..00d69fdfd2c --- /dev/null +++ b/src/com/android/settings/ext/BoolSettingPrefController.java @@ -0,0 +1,90 @@ +/* + * 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 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; + + protected BoolSettingPrefController(Context ctx, String key, BoolSetting setting) { + super(ctx, key); + helper = new ExtSettingControllerHelper(ctx, setting); + this.setting = setting; + } + + @Override + public int getAvailabilityStatus() { + return helper.getAvailabilityStatus(); + } + + @Override + public final boolean isChecked() { + return setting.get(mContext); + } + + @Override + public boolean setChecked(boolean isChecked) { + return setting.put(mContext, 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..250ccb6e29e --- /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 { + private 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..1660f54bf0b --- /dev/null +++ b/src/com/android/settings/ext/IntSettingPrefController.java @@ -0,0 +1,57 @@ +/* + * 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 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) { + super(ctx, key); + this.setting = setting; + helper = new ExtSettingControllerHelper(ctx, setting); + } + + @Override + public int getAvailabilityStatus() { + return helper.getAvailabilityStatus(); + } + + @Override + protected final int getCurrentValue() { + return setting.get(mContext); + } + + @Override + protected boolean setValue(int val) { + return setting.put(mContext, 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 8905c41b906f2fb6a6dc4bb6da2cd693431e9d00 Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Tue, 30 Jul 2024 15:20:39 +0300 Subject: [PATCH 017/112] 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 | 2 ++ .../core/gateway/SettingsGateway.java | 1 + .../dashboard/DashboardFragmentRegistry.java | 3 ++ .../ExploitProtectionFragment.java | 29 +++++++++++++++++++ 7 files changed, 73 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 ffdd7c23dcb..b8dc889ccba 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -2200,6 +2200,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 7678338976a..757aed39dd4 100644 --- a/src/com/android/settings/Settings.java +++ b/src/com/android/settings/Settings.java @@ -515,4 +515,6 @@ public static class ResetMobileNetworkSettingsActivity extends SettingsActivity public static class HearingDevicesActivity extends SettingsActivity { /* empty */ } public static class HearingDevicesPairingActivity extends SettingsActivity { /* empty */ } + + public static class ExploitProtectionActivity extends SettingsActivity {} } diff --git a/src/com/android/settings/core/gateway/SettingsGateway.java b/src/com/android/settings/core/gateway/SettingsGateway.java index 734bddcbb2a..a3e8d81ee71 100644 --- a/src/com/android/settings/core/gateway/SettingsGateway.java +++ b/src/com/android/settings/core/gateway/SettingsGateway.java @@ -214,6 +214,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 849a80b3592..02e42d4c6a2 100644 --- a/src/com/android/settings/dashboard/DashboardFragmentRegistry.java +++ b/src/com/android/settings/dashboard/DashboardFragmentRegistry.java @@ -43,6 +43,7 @@ import com.android.settings.notification.SoundSettings; import com.android.settings.notification.zen.ZenModeSettings; import com.android.settings.privacy.PrivacyDashboardFragment; +import com.android.settings.safetycenter.ExploitProtectionFragment; import com.android.settings.safetycenter.MoreSecurityPrivacyFragment; import com.android.settings.security.LockscreenDashboardFragment; import com.android.settings.security.SecurityAdvancedSettings; @@ -71,6 +72,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 e1cc94871dba73d196a3ccaaf2ef4d42801f519d 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 018/112] 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 7e363e6f238..e04e1a87f73 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -3169,6 +3169,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 019/112] 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 5c66206b4580fec2690cc2095f523259dc8d085d Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Sun, 25 Jul 2021 14:44:48 -0400 Subject: [PATCH 020/112] 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 23ce3017d9a..5b296b50540 100644 --- a/res/values/config.xml +++ b/res/values/config.xml @@ -518,7 +518,7 @@ false - content://com.google.android.gms.nearby.fastpair/device_status_list_item + From a1db5e4613748886893e72bbb43606e86bddd819 Mon Sep 17 00:00:00 2001 From: Your Name Date: Mon, 18 Oct 2021 02:17:56 +0000 Subject: [PATCH 021/112] 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 9362da6bb3617a2b60290e75613e707ec4c9a55a Mon Sep 17 00:00:00 2001 From: Danny Lin Date: Wed, 7 Jul 2021 03:02:05 -0700 Subject: [PATCH 022/112] 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. Requires frameworks/base commit: "Add a config to state whether a device supports increased touch sensitivity." Requires device/google/* commit: "Express support for increased touch sensitivity." Closes: #1 Co-authored-by: Diab Neiroukh Change-Id: I86af721fde33226d314d8a44525f310828299a72 --- res/values/strings.xml | 4 ++ res/xml/display_settings.xml | 6 ++ .../TouchSensitivityPreferenceController.java | 61 +++++++++++++++++++ 3 files changed, 71 insertions(+) create mode 100755 src/com/android/settings/display/TouchSensitivityPreferenceController.java diff --git a/res/values/strings.xml b/res/values/strings.xml index e04e1a87f73..1ee7c84d12b 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -2892,6 +2892,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/xml/display_settings.xml b/res/xml/display_settings.xml index 4e52cf49092..6a068db9be9 100644 --- a/res/xml/display_settings.xml +++ b/res/xml/display_settings.xml @@ -165,6 +165,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 023/112] add dynamic link to sandboxed Google Play settings --- res/values/strings.xml | 3 ++ res/xml/apps.xml | 13 +++++ .../applications/GmsCompatAppController.java | 48 +++++++++++++++++++ 3 files changed, 64 insertions(+) create mode 100644 src/com/android/settings/applications/GmsCompatAppController.java diff --git a/res/values/strings.xml b/res/values/strings.xml index 1ee7c84d12b..2472f8dac05 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -13676,4 +13676,7 @@ Search Settings + + Sandboxed Google Play + Sandboxed Google Play (work profile) diff --git a/res/xml/apps.xml b/res/xml/apps.xml index 2ffd0b1eaba..0598d316a54 100644 --- a/res/xml/apps.xml +++ b/res/xml/apps.xml @@ -124,4 +124,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 79f093e2ef3a0c1127afeb84da42705c0c4e2f39 Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Mon, 12 Aug 2024 17:45:43 +0300 Subject: [PATCH 024/112] 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 53bbc5727d4..3f404d0db6c 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 025/112] 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 3bda9789896..d80f4360aa0 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 0723eec92e4816fda73429bbdda3cf5b5aedbc0d Mon Sep 17 00:00:00 2001 From: Roman Royer Date: Wed, 4 May 2016 19:04:36 -0700 Subject: [PATCH 026/112] 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 6c16d94a51d..4fae58ace18 100644 --- a/src/com/android/settings/applications/manageapplications/ManageApplications.java +++ b/src/com/android/settings/applications/manageapplications/ManageApplications.java @@ -863,9 +863,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 405a5f7b20e0cd85201c39e5c183674fa9e881a9 Mon Sep 17 00:00:00 2001 From: empratyush Date: Wed, 4 May 2022 20:54:16 +0530 Subject: [PATCH 027/112] add missing face unlock strings for English We would need some kind of automation to do this for all languages. --- res/layout/face_enroll_introduction.xml | 4 ++-- res/values/strings.xml | 12 ++++++++++++ .../biometrics/face/FaceEnrollIntroduction.java | 12 ++++++------ 3 files changed, 20 insertions(+), 8 deletions(-) diff --git a/res/layout/face_enroll_introduction.xml b/res/layout/face_enroll_introduction.xml index 8b0352928ca..ea57f4acbc9 100644 --- a/res/layout/face_enroll_introduction.xml +++ b/res/layout/face_enroll_introduction.xml @@ -64,7 +64,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" style="@style/BiometricEnrollIntroTitle" - android:text="@string/security_settings_face_enroll_introduction_info_title" /> + android:text="@string/security_settings_face_enroll_introduction_info_title_en" /> + android:text="@string/security_settings_face_enroll_introduction_how_title_en" /> Use your face to unlock your phone, authorize purchases, or sign in to apps + + Keep in mind + How it works + + Glasses or lightly tinted sunglasses are OK. + Looking at the phone can unlock it even when you don’t intend to. Your phone can also be unlocked by someone who looks a lot like you, like an identical sibling, or if someone holds it up to your face. + Using a face to unlock the phone may be less secure than a strong pattern or PIN. + Face Unlock can require your eyes to be open to unlock the phone or verify it’s you. You can turn this option on at any time in Settings. + Face Unlock creates a unique model of your face to verify it’s you. To create this face model during setup, you will take images of your face from different angles.\n\nWhen you use Face Unlock, images are used to update your face model. Images used to create your face model are not stored, but the face model is stored securely on your phone and never leaves the phone. All processing occurs securely on your phone. + You’re in control + You can delete your face model or turn off Face Unlock at any time in Settings. Face models are stored on the phone until you delete them.\n\nLearn more at g.co/pixel/faceunlock. + diff --git a/src/com/android/settings/biometrics/face/FaceEnrollIntroduction.java b/src/com/android/settings/biometrics/face/FaceEnrollIntroduction.java index d3f75195305..648cb18a241 100644 --- a/src/com/android/settings/biometrics/face/FaceEnrollIntroduction.java +++ b/src/com/android/settings/biometrics/face/FaceEnrollIntroduction.java @@ -365,34 +365,34 @@ protected boolean generateChallengeOnCreate() { @StringRes protected int getInfoMessageGlasses() { - return R.string.security_settings_face_enroll_introduction_info_glasses; + return R.string.security_settings_face_enroll_introduction_info_glasses_en; } @StringRes protected int getInfoMessageLooking() { return isPrivateProfile() ? R.string.private_space_face_enroll_introduction_info_looking - : R.string.security_settings_face_enroll_introduction_info_looking; + : R.string.security_settings_face_enroll_introduction_info_looking_en; } @StringRes protected int getInfoMessageRequireEyes() { - return R.string.security_settings_face_enroll_introduction_info_gaze; + return R.string.security_settings_face_enroll_introduction_info_gaze_en; } @StringRes protected int getHowMessage() { - return R.string.security_settings_face_enroll_introduction_how_message; + return R.string.security_settings_face_enroll_introduction_how_message_en; } @StringRes protected int getInControlTitle() { - return R.string.security_settings_face_enroll_introduction_control_title; + return R.string.security_settings_face_enroll_introduction_control_title_en; } @StringRes protected int getInControlMessage() { - return R.string.security_settings_face_enroll_introduction_control_message; + return R.string.security_settings_face_enroll_introduction_control_message_en; } @StringRes From ebe50bd9f2be397f8d416dfa9e638fdc4bcbee1a Mon Sep 17 00:00:00 2001 From: June Date: Wed, 16 Mar 2022 07:09:46 +0200 Subject: [PATCH 028/112] add a per-user setting for forwarding censored notifs Signed-off-by: June Co-authored-by: inthewaves Co-authored-by: June --- res/values/strings.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.xml b/res/values/strings.xml index fbcb8d1ae1d..662356f51bc 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -13689,6 +13689,9 @@ Search Settings + 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. + Sandboxed Google Play Sandboxed Google Play (work profile) diff --git a/res/xml/user_settings.xml b/res/xml/user_settings.xml index 59217226592..33a7adedb4f 100644 --- a/res/xml/user_settings.xml +++ b/res/xml/user_settings.xml @@ -100,4 +100,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 a0137df728f..fe09642b58a 100644 --- a/src/com/android/settings/users/UserSettings.java +++ b/src/com/android/settings/users/UserSettings.java @@ -139,6 +139,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 SETTING_GUEST_HAS_LOGGED_IN = "systemui.guest_has_logged_in"; @@ -227,6 +229,7 @@ public class UserSettings extends SettingsPreferenceFragment private AddUserWhenLockedPreferenceController mAddUserWhenLockedPreferenceController; private GuestTelephonyPreferenceController mGuestTelephonyPreferenceController; private RemoveGuestOnExitPreferenceController mRemoveGuestOnExitPreferenceController; + private SendCensoredNotificationsToCurrentUserPreferenceController mSendCensoredNotificationsToCurrentUserPreferenceController; private MultiUserTopIntroPreferenceController mMultiUserTopIntroPreferenceController; private TimeoutToDockUserPreferenceController mTimeoutToDockUserPreferenceController; private UserCreatingDialog mUserCreatingDialog; @@ -324,6 +327,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); @@ -334,11 +341,14 @@ public void onCreate(Bundle icicle) { mAddUserWhenLockedPreferenceController.displayPreference(screen); mGuestTelephonyPreferenceController.displayPreference(screen); mRemoveGuestOnExitPreferenceController.displayPreference(screen); + mSendCensoredNotificationsToCurrentUserPreferenceController.displayPreference(screen); mMultiUserTopIntroPreferenceController.displayPreference(screen); mTimeoutToDockUserPreferenceController.displayPreference(screen); screen.findPreference(mAddUserWhenLockedPreferenceController.getPreferenceKey()) .setOnPreferenceChangeListener(mAddUserWhenLockedPreferenceController); + screen.findPreference(mSendCensoredNotificationsToCurrentUserPreferenceController.getPreferenceKey()) + .setOnPreferenceChangeListener(mSendCensoredNotificationsToCurrentUserPreferenceController); screen.findPreference(mGuestTelephonyPreferenceController.getPreferenceKey()) .setOnPreferenceChangeListener(mGuestTelephonyPreferenceController); @@ -420,6 +430,9 @@ public void onResume() { mRemoveGuestOnExitPreferenceController.updateState(screen.findPreference( mRemoveGuestOnExitPreferenceController.getPreferenceKey())); mSwitchBarController.updateState(); + mSendCensoredNotificationsToCurrentUserPreferenceController.updateState(screen.findPreference( + mSendCensoredNotificationsToCurrentUserPreferenceController.getPreferenceKey())); + if (mShouldUpdateUserList) { updateUI(); } @@ -1342,6 +1355,10 @@ void updateUserList() { 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); @@ -1846,6 +1863,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 0563a6f58036a3136da65bb819210fba66da0e78 Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Wed, 17 Aug 2022 12:40:26 -0400 Subject: [PATCH 029/112] fully enable location indicators by default --- .../location/LocationIndicatorsPreferenceController.java | 2 +- .../location/RecentLocationAccessPreferenceController.java | 6 +++--- .../location/RecentLocationAccessSeeAllFragment.java | 6 +++--- .../RecentLocationAccessSeeAllPreferenceController.java | 4 ++-- .../location/RecentLocationRequestPreferenceController.java | 4 ++-- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/com/android/settings/location/LocationIndicatorsPreferenceController.java b/src/com/android/settings/location/LocationIndicatorsPreferenceController.java index 75ffb3a9286..1b1af8f8f73 100644 --- a/src/com/android/settings/location/LocationIndicatorsPreferenceController.java +++ b/src/com/android/settings/location/LocationIndicatorsPreferenceController.java @@ -34,7 +34,7 @@ public LocationIndicatorsPreferenceController(Context context, String preference @Override public boolean isChecked() { return DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_PRIVACY, - Utils.PROPERTY_LOCATION_INDICATORS_ENABLED, false); + Utils.PROPERTY_LOCATION_INDICATORS_ENABLED, true); } @Override diff --git a/src/com/android/settings/location/RecentLocationAccessPreferenceController.java b/src/com/android/settings/location/RecentLocationAccessPreferenceController.java index 3cb30251c51..7b3294fabed 100644 --- a/src/com/android/settings/location/RecentLocationAccessPreferenceController.java +++ b/src/com/android/settings/location/RecentLocationAccessPreferenceController.java @@ -48,7 +48,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; private static class PackageEntryClickedListener implements @@ -86,9 +86,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 998e6f3f541..f5f0c5c6b00 100644 --- a/src/com/android/settings/location/RecentLocationAccessSeeAllPreferenceController.java +++ b/src/com/android/settings/location/RecentLocationAccessSeeAllPreferenceController.java @@ -51,9 +51,9 @@ public class RecentLocationAccessSeeAllPreferenceController public RecentLocationAccessSeeAllPreferenceController(Context context, String key) { super(context, key); 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; mRecentLocationAccesses = RecentAppOpsAccess.createForLocation(context); 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 38928e83d86912fdef532857b3e7a234e21a71c8 Mon Sep 17 00:00:00 2001 From: Pratyush Date: Fri, 19 Aug 2022 11:05:36 +0530 Subject: [PATCH 030/112] 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 662356f51bc..93b6e70aa57 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -11908,6 +11908,8 @@ Preferred network mode: CDMA/EvDo/GSM/WCDMA Preferred network mode: LTE + + Preferred network mode: LTE only Preferred network mode: GSM/WCDMA/LTE @@ -11973,8 +11975,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 7d5230db2b6..a0b88295f4a 100644 --- a/src/com/android/settings/network/telephony/EnabledNetworkModePreferenceController.java +++ b/src/com/android/settings/network/telephony/EnabledNetworkModePreferenceController.java @@ -93,7 +93,7 @@ public EnabledNetworkModePreferenceController(Context context, String key) { @Override public int getAvailabilityStatus() { return getNetworkModePreferenceType(mContext, mSubId) - == NetworkModePreferenceType.EnabledNetworkMode + != NetworkModePreferenceType.PreferredNetworkMode ? AVAILABLE : CONDITIONALLY_UNAVAILABLE; } @@ -289,6 +289,7 @@ public void updateConfig() { } void setPreferenceEntries() { + boolean lteOnlyUnsupported = false; mTelephonyManager = mTelephonyManager.createForSubscriptionId(mSubId); clearAllEntries(); @@ -304,6 +305,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) @@ -323,6 +325,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); @@ -340,6 +343,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) @@ -388,6 +392,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)) { @@ -574,6 +583,9 @@ void setPreferenceValueAndSummary(int networkMode) { break; } case TelephonyManagerConstants.NETWORK_MODE_LTE_ONLY: + setSummary(mShow4gForLTE + ? R.string.network_4G_only : R.string.network_lte_only); + break; case TelephonyManagerConstants.NETWORK_MODE_LTE_WCDMA: if (!mIsGlobalCdma) { setSelectedEntry( @@ -839,6 +851,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(TelephonyManagerConstants.NETWORK_MODE_LTE_ONLY); + } else { + mEntries.add(mContext.getString(R.string.network_lte_only)); + mEntriesValue.add(TelephonyManagerConstants.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 210cd879966..f5c0514525b 100644 --- a/src/com/android/settings/network/telephony/PreferredNetworkModePreferenceController.java +++ b/src/com/android/settings/network/telephony/PreferredNetworkModePreferenceController.java @@ -126,7 +126,7 @@ private int getPreferredNetworkModeSummaryResId(int NetworkMode) { case TelephonyManagerConstants.NETWORK_MODE_LTE_TDSCDMA: return R.string.preferred_network_mode_lte_tdscdma_summary; case TelephonyManagerConstants.NETWORK_MODE_LTE_ONLY: - return R.string.preferred_network_mode_lte_summary; + return R.string.preferred_network_mode_lte_only_summary; case TelephonyManagerConstants.NETWORK_MODE_LTE_TDSCDMA_GSM: return R.string.preferred_network_mode_lte_tdscdma_gsm_summary; case TelephonyManagerConstants.NETWORK_MODE_LTE_TDSCDMA_GSM_WCDMA: From e9b835ae72aac1c49c6e3e7cd3b83065841e5058 Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Sun, 13 Nov 2022 20:24:05 +0200 Subject: [PATCH 031/112] 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 503d5f766f8058818d877840e68c08b43594a1dd Mon Sep 17 00:00:00 2001 From: LuK1337 Date: Thu, 9 Jun 2022 11:27:32 +0200 Subject: [PATCH 032/112] Settings: Pass empty lottie resource for quickly open camera animation This lets us hide it properly. Change-Id: I02ac031a835236811b82a7de283335390ffebab9 --- res/drawable/quickly_open_camera.xml | 3 --- res/raw/lottie_quickly_open_camera.json | 0 res/xml/double_tap_power_settings.xml | 2 +- 3 files changed, 1 insertion(+), 4 deletions(-) delete mode 100644 res/drawable/quickly_open_camera.xml create mode 100644 res/raw/lottie_quickly_open_camera.json diff --git a/res/drawable/quickly_open_camera.xml b/res/drawable/quickly_open_camera.xml deleted file mode 100644 index dcbf9f4dc68..00000000000 --- a/res/drawable/quickly_open_camera.xml +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/res/raw/lottie_quickly_open_camera.json b/res/raw/lottie_quickly_open_camera.json new file mode 100644 index 00000000000..e69de29bb2d diff --git a/res/xml/double_tap_power_settings.xml b/res/xml/double_tap_power_settings.xml index fb5dd52b913..7896046d1cd 100644 --- a/res/xml/double_tap_power_settings.xml +++ b/res/xml/double_tap_power_settings.xml @@ -24,7 +24,7 @@ + app:lottie_rawRes="@raw/lottie_quickly_open_camera"/> Date: Tue, 14 Feb 2023 10:05:57 +0200 Subject: [PATCH 033/112] add a toggle for auto-grants of OTHER_SENSORS permission --- res/values/strings_ext.xml | 4 ++++ res/xml/more_security_privacy_settings.xml | 7 +++++++ 2 files changed, 11 insertions(+) diff --git a/res/values/strings_ext.xml b/res/values/strings_ext.xml index d80f4360aa0..60a38fd4cef 100644 --- a/res/values/strings_ext.xml +++ b/res/values/strings_ext.xml @@ -11,4 +11,8 @@ App exploit protection + 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 f2004937f60..62c6a2a42aa 100644 --- a/res/xml/more_security_privacy_settings.xml +++ b/res/xml/more_security_privacy_settings.xml @@ -91,6 +91,13 @@ settings:controller= "com.android.settings.sound.MediaControlsLockScreenPreferenceController" /> + + Date: Tue, 14 Feb 2023 10:27:56 +0200 Subject: [PATCH 034/112] add a toggle for camera access from the lock screen --- res/values/strings_ext.xml | 2 ++ res/xml/screen_lock_settings.xml | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/res/values/strings_ext.xml b/res/values/strings_ext.xml index 60a38fd4cef..eb282e89d04 100644 --- a/res/values/strings_ext.xml +++ b/res/values/strings_ext.xml @@ -15,4 +15,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/screen_lock_settings.xml b/res/xml/screen_lock_settings.xml index 19061d9b855..d2553f61a25 100644 --- a/res/xml/screen_lock_settings.xml +++ b/res/xml/screen_lock_settings.xml @@ -52,4 +52,9 @@ android:key="power_button_instantly_locks" android:title="@string/lockpattern_settings_enable_power_button_instantly_locks" /> + + From 0b353240d03ec789caa0e2cd71abcc39ef43e97c Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Tue, 14 Feb 2023 11:23:29 +0200 Subject: [PATCH 035/112] 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 eb282e89d04..4cfb702a329 100644 --- a/res/values/strings_ext.xml +++ b/res/values/strings_ext.xml @@ -17,4 +17,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 fbfdaa24225fc3bcb7418001564794107dd594fa Mon Sep 17 00:00:00 2001 From: r3g_5z Date: Sat, 18 Feb 2023 11:09:31 -0500 Subject: [PATCH 036/112] 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 4cfb702a329..813daad375c 100644 --- a/res/values/strings_ext.xml +++ b/res/values/strings_ext.xml @@ -20,4 +20,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 62c6a2a42aa..8a318b293ef 100644 --- a/res/xml/more_security_privacy_settings.xml +++ b/res/xml/more_security_privacy_settings.xml @@ -98,6 +98,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 037/112] 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 813daad375c..2ef5fe0ff9d 100644 --- a/res/values/strings_ext.xml +++ b/res/values/strings_ext.xml @@ -23,4 +23,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 3f26d04287e..07c32921981 100644 --- a/res/xml/location_settings.xml +++ b/res/xml/location_settings.xml @@ -69,6 +69,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 038/112] 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 aba9eddce21..9899357f931 100644 --- a/src/com/android/settings/password/ChooseLockPassword.java +++ b/src/com/android/settings/password/ChooseLockPassword.java @@ -1015,9 +1015,6 @@ private void setAutoPinConfirmOption(boolean enabled, int length) { if (enabled && !mIsAlphaMode && isAutoPinConfirmPossible(length)) { 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 d4456f2c58067824a844db4e831954439e805911 Mon Sep 17 00:00:00 2001 From: r3g_5z Date: Wed, 15 Mar 2023 21:11:12 -0400 Subject: [PATCH 039/112] 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 a2ad25ff96d..a29a118f82e 100644 --- a/src/com/android/settings/display/ScreenResolutionFragment.java +++ b/src/com/android/settings/display/ScreenResolutionFragment.java @@ -101,7 +101,6 @@ protected int getPreferenceScreenResId() { @Override protected void addStaticPreferences(PreferenceScreen screen) { - updateIllustrationImage(mImagePreference); screen.addPreference(mImagePreference); final FooterPreference footerPreference = new FooterPreference(screen.getContext()); @@ -223,7 +222,6 @@ protected boolean setDefaultKey(final String key) { } setDisplayMode(width); - updateIllustrationImage(mImagePreference); return true; } From 7f8849543f5a3a5066c6d6072e0c6c392b3a398d Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Wed, 24 Jan 2024 19:13:22 +0200 Subject: [PATCH 040/112] 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 2ef5fe0ff9d..9c72938e5aa 100644 --- a/res/values/strings_ext.xml +++ b/res/values/strings_ext.xml @@ -31,4 +31,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 292f1824552..f4dd624a265 100644 --- a/res/xml/network_provider_internet.xml +++ b/res/xml/network_provider_internet.xml @@ -55,6 +55,14 @@ settings:useAdminDisabledSummary="true" settings:controller="com.android.settings.network.MobileNetworkSummaryController" /> + + setEnabled(isChecked)); + b.show(); + + return false; + } +} From 1e42d374244fe4b62825f4404adad056aebaf2b3 Mon Sep 17 00:00:00 2001 From: r3g_5z Date: Sun, 2 Apr 2023 22:23:41 -0400 Subject: [PATCH 041/112] 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 9c72938e5aa..0863ddb28cc 100644 --- a/res/values/strings_ext.xml +++ b/res/values/strings_ext.xml @@ -49,4 +49,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 f4dd624a265..288b02d7d90 100644 --- a/res/xml/network_provider_internet.xml +++ b/res/xml/network_provider_internet.xml @@ -124,4 +124,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 55cd3adde48f412c06c268daf4ce67f8019574fa Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Thu, 6 Apr 2023 12:11:09 +0300 Subject: [PATCH 042/112] 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 0863ddb28cc..e6f3d6a9044 100644 --- a/res/values/strings_ext.xml +++ b/res/values/strings_ext.xml @@ -54,4 +54,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 7e8969de07d..cc630f79ff0 100644 --- a/res/xml/special_access.xml +++ b/res/xml/special_access.xml @@ -226,4 +226,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 e8dfec5c9232b529522bdca92114c9e777711626 Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Wed, 3 May 2023 08:57:01 +0300 Subject: [PATCH 043/112] add GNSS PSDS setting --- res/values/strings_ext.xml | 11 ++++ res/xml/location_settings.xml | 5 ++ .../location/GnssPsdsPrefController.java | 58 +++++++++++++++++++ 3 files changed, 74 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 e6f3d6a9044..c4f04ee852e 100644 --- a/res/values/strings_ext.xml +++ b/res/values/strings_ext.xml @@ -69,4 +69,15 @@ 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 + Qualcomm 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 07c32921981..4c99a9ae6a6 100644 --- a/res/xml/location_settings.xml +++ b/res/xml/location_settings.xml @@ -74,6 +74,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 044/112] 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 c4f04ee852e..4b18be00da1 100644 --- a/res/values/strings_ext.xml +++ b/res/values/strings_ext.xml @@ -80,4 +80,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 288b02d7d90..876388d5d52 100644 --- a/res/xml/network_provider_internet.xml +++ b/res/xml/network_provider_internet.xml @@ -125,6 +125,12 @@ android:order="30" settings:controller="com.android.settings.network.CellularSecurityPreferenceController"/> + + Date: Wed, 24 May 2023 14:57:01 +0300 Subject: [PATCH 045/112] 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 4b18be00da1..6a3212d86c6 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 7b6c7651b6b44f3dabff98c6d59dc94e17ff8268 Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Thu, 25 May 2023 16:25:33 +0300 Subject: [PATCH 046/112] 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 6a3212d86c6..b6d8f88afab 100644 --- a/res/values/strings_ext.xml +++ b/res/values/strings_ext.xml @@ -91,4 +91,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 1e1c9e097f4e2d5c52bf569c657a8cec78b55101 Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Wed, 24 May 2023 15:01:04 +0300 Subject: [PATCH 047/112] 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 b6d8f88afab..5c41c20f89a 100644 --- a/res/values/strings_ext.xml +++ b/res/values/strings_ext.xml @@ -93,4 +93,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 dfb41ed8ceb309102e3801915fe94340b765d7c8 Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Wed, 24 May 2023 18:23:22 +0300 Subject: [PATCH 048/112] add deny_new_usb setting --- res/values/strings_ext.xml | 7 ++ res/xml/exploit_protection_settings.xml | 5 ++ .../security/DenyNewUsbPrefController.java | 79 +++++++++++++++++++ 3 files changed, 91 insertions(+) create mode 100644 src/com/android/settings/security/DenyNewUsbPrefController.java diff --git a/res/values/strings_ext.xml b/res/values/strings_ext.xml index 5c41c20f89a..8400bc442ea 100644 --- a/res/values/strings_ext.xml +++ b/res/values/strings_ext.xml @@ -99,4 +99,11 @@ 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." + USB peripherals + This feature exists to reduce attack surface, especially for a locked device. + + Allow new USB peripherals + Allow new USB peripherals when unlocked + Disallow new USB peripherals + diff --git a/res/xml/exploit_protection_settings.xml b/res/xml/exploit_protection_settings.xml index bfd7e4dc3d9..92c4f55850c 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" /> + + list = Arrays.asList( + DenyNewUsbSetting.DISABLED, + DenyNewUsbSetting.DYNAMIC, + DenyNewUsbSetting.ENABLED + ); + + public DenyNewUsbPrefController(Context ctx, String key) { + super(ctx, key); + } + + @Override + public int getAvailabilityStatus() { + return getGlobalSettingAvailability(mContext); + } + + @Override + protected void getEntries(Entries entries) { + entries.add(R.string.deny_new_usb_val_enabled, list.indexOf(DenyNewUsbSetting.ENABLED)); + entries.add(R.string.deny_new_usb_val_dynamic, list.indexOf(DenyNewUsbSetting.DYNAMIC)); + entries.add(R.string.deny_new_usb_val_disabled, list.indexOf(DenyNewUsbSetting.DISABLED)); + } + + @Override + public void addPrefsAfterList(RadioButtonPickerFragment2 fragment, PreferenceScreen screen) { + addFooterPreference(screen, R.string.deny_new_usb_footer, + "https://grapheneos.org/usage#usb-peripherals"); + } + + @Override + protected int getCurrentValue() { + return list.indexOf(DenyNewUsbSetting.SYS_PROP.get()); + } + + @Override + protected boolean setValue(int val) { + String strVal = list.get(val); + boolean res = DenyNewUsbSetting.SYS_PROP.put(strVal); + if (!res) { + return false; + } + if (DenyNewUsbSetting.DYNAMIC.equals(strVal)) { + // when "dynamic" is written to the sysprop, the following hook is triggered in + // system/core/rootdir/init.rc : + + // on property:persist.security.deny_new_usb=dynamic + // - write /proc/sys/kernel/deny_new_usb 1 + + // But the fact that the setting was set by the user implies that the device is unlocked, + // and deny_new_usb should be disabled until the device gets locked + SystemProperties.set(DenyNewUsbSetting.TRANSIENT_PROP, + DenyNewUsbSetting.TRANSIENT_DISABLE); + } + return true; + } + + @Override + protected boolean isCredentialConfirmationRequired() { + return true; + } +} From 3609b86c07a2ac435fb65b082bdcaf9996db2232 Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Tue, 18 Jun 2024 15:32:22 +0300 Subject: [PATCH 049/112] hide deny_new_usb setting when USB-C port setting is available --- .../settings/security/DenyNewUsbPrefController.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/com/android/settings/security/DenyNewUsbPrefController.java b/src/com/android/settings/security/DenyNewUsbPrefController.java index 90d49dd8053..26d9ea0788a 100644 --- a/src/com/android/settings/security/DenyNewUsbPrefController.java +++ b/src/com/android/settings/security/DenyNewUsbPrefController.java @@ -23,12 +23,21 @@ public class DenyNewUsbPrefController extends AbstractListPreferenceController { DenyNewUsbSetting.ENABLED ); + private final boolean isUsbPortSecuritySupported; + public DenyNewUsbPrefController(Context ctx, String key) { super(ctx, key); + + isUsbPortSecuritySupported = mContext.getResources().getBoolean( + com.android.internal.R.bool.config_usbPortSecuritySupported); } @Override public int getAvailabilityStatus() { + if (isUsbPortSecuritySupported) { + return UNSUPPORTED_ON_DEVICE; + } + return getGlobalSettingAvailability(mContext); } From 287c9ed69178d9b8d79661ccbca4dda82ad63ef4 Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Thu, 25 May 2023 16:47:42 +0300 Subject: [PATCH 050/112] 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 8400bc442ea..bb0cf3d83a7 100644 --- a/res/values/strings_ext.xml +++ b/res/values/strings_ext.xml @@ -106,4 +106,8 @@ There are HTTP, HTTPS, DNS, DNS-over-TLS and DNS-over-HTTPS connectivity checks. Allow new USB peripherals when unlocked Disallow new USB peripherals + 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 92c4f55850c..9c71884b329 100644 --- a/res/xml/exploit_protection_settings.xml +++ b/res/xml/exploit_protection_settings.xml @@ -29,7 +29,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 ab9587d2984224b7d11a599662410016f5460be7 Mon Sep 17 00:00:00 2001 From: flawedworld Date: Sun, 25 Jun 2023 13:53:58 +0100 Subject: [PATCH 051/112] 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 e789f72c11453f4541bd46aac88642f9cc7cbe27 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 052/112] Remove "Add users from lock screen" setting --- .../users/AddUserWhenLockedPreferenceController.java | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/src/com/android/settings/users/AddUserWhenLockedPreferenceController.java b/src/com/android/settings/users/AddUserWhenLockedPreferenceController.java index fe90a2a25b8..ef54f0b2755 100644 --- a/src/com/android/settings/users/AddUserWhenLockedPreferenceController.java +++ b/src/com/android/settings/users/AddUserWhenLockedPreferenceController.java @@ -59,15 +59,7 @@ public void updateState(Preference preference) { @Override public int getAvailabilityStatus() { - if (!mUserCaps.isAdmin()) { - return DISABLED_FOR_USER; - } else if (android.multiuser.Flags.newMultiuserSettingsUx()) { - return AVAILABLE; - } else if (mUserCaps.disallowAddUser() || mUserCaps.disallowAddUserSetByAdmin()) { - return DISABLED_FOR_USER; - } else { - return mUserCaps.mUserSwitcherEnabled ? AVAILABLE : CONDITIONALLY_UNAVAILABLE; - } + return UNSUPPORTED_ON_DEVICE; } @Override From 47236830391b885d1b1975fdf124d8a673053ff0 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 053/112] Factor out common code for reading/writing UserManager restrictions --- .../settings/users/UserDetailsSettings.java | 2 + .../settings/users/UserRestrictions.java | 38 +++++++++++++++++++ 2 files changed, 40 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 8afab9678f4..17ed8008f23 100644 --- a/src/com/android/settings/users/UserDetailsSettings.java +++ b/src/com/android/settings/users/UserDetailsSettings.java @@ -102,6 +102,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() { @@ -344,6 +345,7 @@ void initialize(Context context, Bundle arguments) { boolean isNewUser = arguments.getBoolean(AppRestrictionsFragment.EXTRA_NEW_USER, false); mUserInfo = mUserManager.getUserInfo(userId); + userRestrictions = new UserRestrictions(mUserManager, mUserInfo); mSwitchUserPref = findPreference(KEY_SWITCH_USER); mPhonePref = findPreference(KEY_ENABLE_TELEPHONY); diff --git a/src/com/android/settings/users/UserRestrictions.java b/src/com/android/settings/users/UserRestrictions.java new file mode 100644 index 00000000000..7db3161c201 --- /dev/null +++ b/src/com/android/settings/users/UserRestrictions.java @@ -0,0 +1,38 @@ +package com.android.settings.users; + +import android.content.pm.UserInfo; +import android.os.Bundle; +import android.os.UserHandle; +import android.os.UserManager; + +import java.util.List; + +final class UserRestrictions { + + final UserManager userManager; + final UserInfo userInfo; + + UserRestrictions(UserManager userManager, UserInfo userInfo) { + this.userManager = userManager; + this.userInfo = userInfo; + } + + boolean isSet(String restrictionKey) { + final boolean isSetFromUser = userManager.hasUserRestriction(restrictionKey, userInfo.getUserHandle()); + if (userInfo.isGuest()) { + return isSetFromUser || userManager.getDefaultGuestRestrictions().getBoolean(restrictionKey); + } + + return isSetFromUser; + } + + 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 f5970d7b6cb97f99ceeff462fa11fdbb0535ec26 Mon Sep 17 00:00:00 2001 From: Pratyush Date: Sat, 3 Sep 2022 15:52:37 +0530 Subject: [PATCH 054/112] 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 17ed8008f23..224e448292e 100644 --- a/src/com/android/settings/users/UserDetailsSettings.java +++ b/src/com/android/settings/users/UserDetailsSettings.java @@ -78,7 +78,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; private UserManager mUserManager; @@ -422,7 +422,6 @@ void initialize(Context context, Bundle arguments) { mPhonePref.setChecked(!mUserManager.hasUserRestriction( UserManager.DISALLOW_OUTGOING_CALLS, new UserHandle(userId))); mRemoveUserPref.setTitle(R.string.user_remove_user); - removePreference(KEY_APP_COPYING); } // Remove preference KEY_REMOVE_USER if DISALLOW_REMOVE_USER restriction is set From f722b1c2f3347b80ce2141334436066cabbee099 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 055/112] UserManager settings for apps installs and updates --- res/values/strings_ext.xml | 11 ++ res/xml/user_details_settings.xml | 4 + .../users/UserAppsInstallSettings.java | 173 ++++++++++++++++++ .../settings/users/UserDetailsSettings.java | 11 ++ 4 files changed, 199 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 bb0cf3d83a7..a6b1b95d860 100644 --- a/res/values/strings_ext.xml +++ b/res/values/strings_ext.xml @@ -110,4 +110,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 224e448292e..301484ee6c2 100644 --- a/src/com/android/settings/users/UserDetailsSettings.java +++ b/src/com/android/settings/users/UserDetailsSettings.java @@ -66,6 +66,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"; @@ -98,6 +100,7 @@ public class UserDetailsSettings extends SettingsPreferenceFragment Preference mRemoveUserPref; @VisibleForTesting TwoStatePreference mGrantAdminPref; + Preference mAppsInstallsPref; @VisibleForTesting /** The user being studied (not the user doing the studying). */ @@ -135,6 +138,8 @@ public void onResume() { if (mUserInfo.isGuest() && mGuestUserAutoCreated) { mRemoveUserPref.setEnabled((mUserInfo.flags & UserInfo.FLAG_INITIALIZED) != 0); } + mAppsInstallsPref.setSummary(UserAppsInstallSettings.getDescription( + requireContext(), userRestrictions)); } @Override @@ -175,6 +180,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; } @@ -355,6 +363,7 @@ void initialize(Context context, Bundle arguments) { mGrantAdminPref = findPreference(KEY_GRANT_ADMIN); mGrantAdminPref.setChecked(mUserInfo.isAdmin()); + mAppsInstallsPref = findPreference(KEY_APP_INSTALLS); mSwitchUserPref.setTitle( context.getString(com.android.settingslib.R.string.user_switch_to_user, @@ -389,6 +398,7 @@ void initialize(Context context, Bundle arguments) { removePreference(KEY_REMOVE_USER); 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); @@ -433,6 +443,7 @@ void initialize(Context context, Bundle arguments) { } mRemoveUserPref.setOnPreferenceClickListener(this); + mAppsInstallsPref.setOnPreferenceClickListener(this); mPhonePref.setOnPreferenceChangeListener(this); mGrantAdminPref.setOnPreferenceChangeListener(this); mAppAndContentAccessPref.setOnPreferenceClickListener(this); From 1ebe06ac725cbe3d22f26e819fcf5ce47a02327d 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 056/112] 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 a6b1b95d860..226058ad89b 100644 --- a/res/values/strings_ext.xml +++ b/res/values/strings_ext.xml @@ -120,5 +120,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 057/112] 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 cebec17d645..8368e0448d4 100644 --- a/src/com/android/settings/users/UserDetailsSettings.java +++ b/src/com/android/settings/users/UserDetailsSettings.java @@ -143,6 +143,7 @@ public void onResume() { } mAppsInstallsPref.setSummary(UserAppsInstallSettings.getDescription( requireContext(), userRestrictions)); + mAppCopyingPref.setEnabled(!userRestrictions.isSet(UserManager.DISALLOW_INSTALL_APPS)); } @Override From 89bbea89db595ecc4bf1dee885bcedb3817fe498 Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Sat, 2 Mar 2024 11:24:34 +0200 Subject: [PATCH 058/112] 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 ea09e9462483fc5a9c82804c79eda925a24722e6 Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Sat, 2 Mar 2024 12:29:45 +0200 Subject: [PATCH 059/112] 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 e5b60f2917bac8aca7f9756b4d44ceb735a27043 Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Sat, 2 Mar 2024 11:19:46 +0200 Subject: [PATCH 060/112] add Storage Scopes link to the "App info" screen --- res/values/strings.xml | 2 ++ .../spa/app/appinfo/AppInfoSettings.kt | 1 + .../app/appinfo/AppStorageScopesPreference.kt | 31 +++++++++++++++++++ 3 files changed, 34 insertions(+) create mode 100644 src/com/android/settings/spa/app/appinfo/AppStorageScopesPreference.kt diff --git a/res/values/strings.xml b/res/values/strings.xml index 93b6e70aa57..ba087e245f6 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -13700,4 +13700,6 @@ Sandboxed Google Play Sandboxed Google Play (work profile) + + Storage Scopes diff --git a/src/com/android/settings/spa/app/appinfo/AppInfoSettings.kt b/src/com/android/settings/spa/app/appinfo/AppInfoSettings.kt index fa9cee2c899..7762a615152 100644 --- a/src/com/android/settings/spa/app/appinfo/AppInfoSettings.kt +++ b/src/com/android/settings/spa/app/appinfo/AppInfoSettings.kt @@ -144,6 +144,7 @@ private fun AppInfoSettings(packageInfoPresenter: PackageInfoPresenter) { AppAllServicesPreference(app) AppNotificationPreference(app) AppPermissionPreference(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..5f759248a89 --- /dev/null +++ b/src/com/android/settings/spa/app/appinfo/AppStorageScopesPreference.kt @@ -0,0 +1,31 @@ +package com.android.settings.spa.app.appinfo + +import android.app.StorageScope +import android.content.pm.ApplicationInfo +import android.content.pm.GosPackageState +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)?.hasFlags(GosPackageState.FLAG_STORAGE_SCOPES_ENABLED) != true) { + 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 d2536e3d254e20a65074f8c736d709f1adf843f4 Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Sat, 2 Mar 2024 11:20:31 +0200 Subject: [PATCH 061/112] 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 f4b16bb6a2695f7eb61f593e728a984bdc8e06b3 Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Fri, 8 Jul 2022 13:40:22 +0300 Subject: [PATCH 062/112] add OBB access toggle to "Install unknown apps" screen --- res/values/strings.xml | 3 ++ .../app/specialaccess/InstallUnknownApps.kt | 51 ++++++++++++++++++- 2 files changed, 53 insertions(+), 1 deletion(-) diff --git a/res/values/strings.xml b/res/values/strings.xml index ba087e245f6..b24a59e862c 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -13702,4 +13702,7 @@ Sandboxed Google Play (work profile) Storage Scopes + + 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 06d5b488e73..af109d0313e 100644 --- a/src/com/android/settings/spa/app/specialaccess/InstallUnknownApps.kt +++ b/src/com/android/settings/spa/app/specialaccess/InstallUnknownApps.kt @@ -22,10 +22,17 @@ 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.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 +51,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(GosPackageState.FLAG_ALLOW_ACCESS_TO_OBB_DIRECTORY) == true + } + + fun setObbFlagState(state: Boolean): Boolean { + GosPackageState.edit(app.packageName, app.userId).run { + setFlagsState(GosPackageState.FLAG_ALLOW_ACCESS_TO_OBB_DIRECTORY, state) + killUidAfterApply() + if (apply()) { + isObbFlagSet.value = state + return true + } else { + return false + } + } + } +} class InstallUnknownAppsListModel(private val context: Context) : TogglePermissionAppListModel { @@ -83,6 +109,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 cd429cc5b9f56627b036aedd7aa33cc12917e684 Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Sat, 2 Mar 2024 11:22:22 +0200 Subject: [PATCH 063/112] add Contact Scopes link to the "App info" screen --- res/values/strings_ext.xml | 2 ++ .../app/appinfo/AppContactScopesPreference.kt | 31 +++++++++++++++++++ .../spa/app/appinfo/AppInfoSettings.kt | 1 + 3 files changed, 34 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 226058ad89b..1f835852b3b 100644 --- a/res/values/strings_ext.xml +++ b/res/values/strings_ext.xml @@ -81,6 +81,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 + GrapheneOS server Standard (Google) server Off 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..e898f4e9086 --- /dev/null +++ b/src/com/android/settings/spa/app/appinfo/AppContactScopesPreference.kt @@ -0,0 +1,31 @@ +package com.android.settings.spa.app.appinfo + +import android.content.pm.ApplicationInfo +import android.content.pm.GosPackageState +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)?.hasFlags(GosPackageState.FLAG_CONTACT_SCOPES_ENABLED) != true) { + 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 7762a615152..c141682983c 100644 --- a/src/com/android/settings/spa/app/appinfo/AppInfoSettings.kt +++ b/src/com/android/settings/spa/app/appinfo/AppInfoSettings.kt @@ -145,6 +145,7 @@ private fun AppInfoSettings(packageInfoPresenter: PackageInfoPresenter) { AppNotificationPreference(app) AppPermissionPreference(app) AppStorageScopesPreference(app) + AppContactScopesPreference(app) AppStoragePreference(app) InstantAppDomainsPreference(app) AppDataUsagePreference(app) From 39cccdfe8553193d5e7d4bd911d4957b73e56299 Mon Sep 17 00:00:00 2001 From: empratyush Date: Mon, 20 Jun 2022 22:16:29 +0300 Subject: [PATCH 064/112] Reverse Wireless Charging UI --- Android.bp | 1 + res/values/strings.xml | 3 + res/xml/power_usage_summary.xml | 6 ++ .../BatterySharePreferenceController.java | 99 +++++++++++++++++++ 4 files changed, 109 insertions(+) create mode 100644 src/com/android/settings/display/BatterySharePreferenceController.java diff --git a/Android.bp b/Android.bp index 0a58ee8ea7c..a2674311970 100644 --- a/Android.bp +++ b/Android.bp @@ -92,6 +92,7 @@ android_library { // Settings dependencies "FingerprintManagerInteractor", "MediaDrmSettingsFlagsLib", + "ReverseWirelessCharging", "Settings-change-ids", "SettingsLib", "SettingsLibActivityEmbedding", diff --git a/res/values/strings.xml b/res/values/strings.xml index b24a59e862c..b97d521730f 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -13705,4 +13705,7 @@ 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 77c6b7322c2..7245528bd47 100644 --- a/res/xml/power_usage_summary.xml +++ b/res/xml/power_usage_summary.xml @@ -64,6 +64,12 @@ android:summary="@string/battery_percentage_description" 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 5bc32e5d9088cf8c3624bf77f17f24d963053019 Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Fri, 15 Sep 2023 10:03:16 +0300 Subject: [PATCH 065/112] 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 5b296b50540..2af7dbe3d83 100644 --- a/res/values/config.xml +++ b/res/values/config.xml @@ -612,7 +612,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. + 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 059201f8f0a127a24871c59a787742db72e4f4eb Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Wed, 15 Nov 2023 13:44:08 +0200 Subject: [PATCH 068/112] 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 e059a191b8281812dd69e941e9b66698d2b4391e Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Wed, 15 Nov 2023 13:44:23 +0200 Subject: [PATCH 069/112] infrastructure for AppSwitch UIs Squashed with 28baa8dcbf5a0d285d8bf3852b723beaa290a973 by quh4gko8 <88831734+quh4gko8@users.noreply.github.com> --- res/values/strings_app_exploit_protection.xml | 34 +++ .../settings/applications/AswAdapter.kt | 86 +++++++ .../applications/AswAppInfoFragment.java | 224 ++++++++++++++++++ .../AswAppListPrefController.java | 27 +++ .../AswExploitProtectionFragment.java | 44 ++++ .../spa/app/appinfo/AppInfoSettings.kt | 3 + .../settings/spa/app/appinfo/AswAppList.kt | 96 ++++++++ .../settings/spa/app/appinfo/AswPreference.kt | 27 +++ .../spa/app/appinfo/PackageInfoPresenter.kt | 5 +- 9 files changed, 545 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..846a4468980 --- /dev/null +++ b/res/values/strings_app_exploit_protection.xml @@ -0,0 +1,34 @@ + + + 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. + + Block for third-party apps by default + Restrict for third-party apps by default + Disable for third-party apps by default + Restricted by default + 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..57749a8b2f5 --- /dev/null +++ b/src/com/android/settings/applications/AswAdapter.kt @@ -0,0 +1,86 @@ +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!! + + 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..4d1fd861abe --- /dev/null +++ b/src/com/android/settings/applications/AswAppInfoFragment.java @@ -0,0 +1,224 @@ +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)); + } + 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 c141682983c..de6af35a0ba 100644 --- a/src/com/android/settings/spa/app/appinfo/AppInfoSettings.kt +++ b/src/com/android/settings/spa/app/appinfo/AppInfoSettings.kt @@ -43,6 +43,7 @@ import com.android.settings.spa.app.specialaccess.InstallUnknownAppsListProvider import com.android.settings.spa.app.specialaccess.ModifySystemSettingsAppListProvider import com.android.settings.spa.app.specialaccess.PictureInPictureListProvider 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 @@ -120,6 +121,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..e69f7f36803 --- /dev/null +++ b/src/com/android/settings/spa/app/appinfo/AswAppList.kt @@ -0,0 +1,96 @@ +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 -> + AppRecordImpl(app, GosPackageState.get(app.packageName, userId)) + } + } + } + + 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 8dbcb14e83b..02a0ffde6ad 100644 --- a/src/com/android/settings/spa/app/appinfo/PackageInfoPresenter.kt +++ b/src/com/android/settings/spa/app/appinfo/PackageInfoPresenter.kt @@ -42,6 +42,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 @@ -94,7 +95,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 0707d9bde5ca9207bbe03414c58f74361038b061 Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Sat, 2 Mar 2024 12:09:48 +0200 Subject: [PATCH 070/112] 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 de6af35a0ba..778d7915e9b 100644 --- a/src/com/android/settings/spa/app/appinfo/AppInfoSettings.kt +++ b/src/com/android/settings/spa/app/appinfo/AppInfoSettings.kt @@ -172,6 +172,9 @@ private fun AppInfoSettings(packageInfoPresenter: PackageInfoPresenter) { AlarmsAndRemindersAppListProvider.InfoPageEntryItem(app) } + Category(title = stringResource(R.string.exploit_protection_category_title)) { + } + Category(title = stringResource(R.string.app_install_details_group_title)) { AppInstallerInfoPreference(app) } From a5f574cc8a3fe5d822b8260f2106714095a502f3 Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Tue, 26 Sep 2023 10:34:50 +0300 Subject: [PATCH 071/112] add per-app setting for exploit protection compatibility mode --- res/values/strings_app_exploit_protection.xml | 1 + ...oitProtectionCompatModeSwitchPreference.kt | 58 +++++++++++++++++++ .../spa/app/appinfo/AppInfoSettings.kt | 1 + 3 files changed, 60 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 846a4468980..0f1cb79f559 100644 --- a/res/values/strings_app_exploit_protection.xml +++ b/res/values/strings_app_exploit_protection.xml @@ -31,4 +31,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..d7a8b482f3f --- /dev/null +++ b/src/com/android/settings/spa/app/appinfo/AppExploitProtectionCompatModeSwitchPreference.kt @@ -0,0 +1,58 @@ +package com.android.settings.spa.app.appinfo + +import android.content.pm.ApplicationInfo +import android.content.pm.GosPackageState +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 = GosPackageState.FLAG_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) == true + } + + override val onCheckedChange = { newChecked: Boolean -> + val action = Runnable { + GosPackageState.edit(pkgName, userId).run { + setFlagsState(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 778d7915e9b..a4943348f1a 100644 --- a/src/com/android/settings/spa/app/appinfo/AppInfoSettings.kt +++ b/src/com/android/settings/spa/app/appinfo/AppInfoSettings.kt @@ -173,6 +173,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 5aaaa6605105718d53da821ff9568280577b1a47 Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Sat, 7 Oct 2023 21:28:08 +0300 Subject: [PATCH 072/112] 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 ec5783e3b81..32ddcc4b8d6 100644 --- a/res/values/strings_ext.xml +++ b/res/values/strings_ext.xml @@ -125,6 +125,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. diff --git a/res/xml/more_security_privacy_settings.xml b/res/xml/more_security_privacy_settings.xml index 8a318b293ef..7f6cf2cf35b 100644 --- a/res/xml/more_security_privacy_settings.xml +++ b/res/xml/more_security_privacy_settings.xml @@ -231,6 +231,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 073/112] 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 | 3 +- 8 files changed, 91 insertions(+), 1 deletion(-) create mode 100644 src/com/android/settings/applications/AppHardenedMalloc.kt diff --git a/AndroidManifest.xml b/AndroidManifest.xml index b8dc889ccba..5b002e21433 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -5389,5 +5389,23 @@ + + + + + + + + + + + + + diff --git a/res/values/strings_app_exploit_protection.xml b/res/values/strings_app_exploit_protection.xml index 0f1cb79f559..b4398acf37c 100644 --- a/res/values/strings_app_exploit_protection.xml +++ b/res/values/strings_app_exploit_protection.xml @@ -32,4 +32,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 9c71884b329..6832b262e93 100644 --- a/res/xml/exploit_protection_settings.xml +++ b/res/xml/exploit_protection_settings.xml @@ -29,6 +29,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 a3e8d81ee71..1d13da6bcf6 100644 --- a/src/com/android/settings/core/gateway/SettingsGateway.java +++ b/src/com/android/settings/core/gateway/SettingsGateway.java @@ -214,6 +214,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 8b481797907..4baac2286f3 100644 --- a/src/com/android/settings/spa/SettingsSpaEnvironment.kt +++ b/src/com/android/settings/spa/SettingsSpaEnvironment.kt @@ -100,6 +100,7 @@ open class SettingsSpaEnvironment(context: Context) : SpaEnvironment(context) { open fun settingsPageProviders() = 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 a4943348f1a..b88824f9d86 100644 --- a/src/com/android/settings/spa/app/appinfo/AppInfoSettings.kt +++ b/src/com/android/settings/spa/app/appinfo/AppInfoSettings.kt @@ -174,6 +174,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)) { @@ -184,4 +185,4 @@ private fun AppInfoSettings(packageInfoPresenter: PackageInfoPresenter) { } fun isArchivingEnabled(featureFlags: PmFeatureFlags) = - featureFlags.archiving() || Flags.appArchiving() \ No newline at end of file + featureFlags.archiving() || Flags.appArchiving() From e82288ab4baf86c5381550d29799e599de5ebb24 Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Fri, 30 Aug 2024 16:23:56 +0300 Subject: [PATCH 074/112] 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 b4398acf37c..57f4e86c950 100644 --- a/res/values/strings_app_exploit_protection.xml +++ b/res/values/strings_app_exploit_protection.xml @@ -40,4 +40,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 6832b262e93..ba6b4dc0dfa 100644 --- a/res/xml/exploit_protection_settings.xml +++ b/res/xml/exploit_protection_settings.xml @@ -34,6 +34,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 4baac2286f3..3d6c6d435fa 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) { 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 b88824f9d86..05e944eeea1 100644 --- a/src/com/android/settings/spa/app/appinfo/AppInfoSettings.kt +++ b/src/com/android/settings/spa/app/appinfo/AppInfoSettings.kt @@ -175,6 +175,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 912ee2a5538140c0fa51ed2bf26ff92c584c8c4f Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Wed, 15 Nov 2023 13:51:07 +0200 Subject: [PATCH 075/112] 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 5b002e21433..1368795bed5 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -5390,6 +5390,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 ba6b4dc0dfa..148b3a5c00f 100644 --- a/res/xml/exploit_protection_settings.xml +++ b/res/xml/exploit_protection_settings.xml @@ -39,6 +39,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 1d13da6bcf6..d59b7295277 100644 --- a/src/com/android/settings/core/gateway/SettingsGateway.java +++ b/src/com/android/settings/core/gateway/SettingsGateway.java @@ -214,6 +214,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 3d6c6d435fa..81903ad379f 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) { 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 05e944eeea1..901e723e5e5 100644 --- a/src/com/android/settings/spa/app/appinfo/AppInfoSettings.kt +++ b/src/com/android/settings/spa/app/appinfo/AppInfoSettings.kt @@ -176,6 +176,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 a4266a870322f45537b94862b8312dcbd7e50712 Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Fri, 30 Aug 2024 16:25:59 +0300 Subject: [PATCH 076/112] 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 1368795bed5..666136f63c2 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -5407,6 +5407,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 148b3a5c00f..39d31713b9a 100644 --- a/res/xml/exploit_protection_settings.xml +++ b/res/xml/exploit_protection_settings.xml @@ -34,6 +34,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 d59b7295277..d18c60fccab 100644 --- a/src/com/android/settings/core/gateway/SettingsGateway.java +++ b/src/com/android/settings/core/gateway/SettingsGateway.java @@ -215,6 +215,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 81903ad379f..9e8f928bc38 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) { 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 901e723e5e5..74444f7c153 100644 --- a/src/com/android/settings/spa/app/appinfo/AppInfoSettings.kt +++ b/src/com/android/settings/spa/app/appinfo/AppInfoSettings.kt @@ -175,6 +175,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 c3c3eb2b09657553e06d72a3c2ab98afeecc8643 Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Mon, 27 Nov 2023 21:47:26 +0200 Subject: [PATCH 077/112] 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 32ddcc4b8d6..f577e9801b4 100644 --- a/res/values/strings_ext.xml +++ b/res/values/strings_ext.xml @@ -133,4 +133,7 @@ There are HTTP, HTTPS, DNS, DNS-over-TLS and DNS-over-HTTPS connectivity checks. "Warning: enabling this setting might cause some apps to stop working. + 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 7f6cf2cf35b..342d8841755 100644 --- a/res/xml/more_security_privacy_settings.xml +++ b/res/xml/more_security_privacy_settings.xml @@ -231,6 +231,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 078/112] 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 f577e9801b4..eb043a8fb1b 100644 --- a/res/values/strings_ext.xml +++ b/res/values/strings_ext.xml @@ -112,6 +112,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 876388d5d52..2975c643ffb 100644 --- a/res/xml/network_provider_internet.xml +++ b/res/xml/network_provider_internet.xml @@ -136,4 +136,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 a193debf3b13596ef0caee088562742ed2bdcd1f Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Mon, 18 Dec 2023 15:38:16 +0200 Subject: [PATCH 079/112] 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 2855f0ab16a..2f7dd6ff789 100644 --- a/src/com/android/settings/connecteddevice/AdvancedConnectedDeviceController.java +++ b/src/com/android/settings/connecteddevice/AdvancedConnectedDeviceController.java @@ -34,7 +34,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); @@ -59,7 +58,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 @@ -68,13 +67,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 6edd33d17b54d529f2f6ef8315a50dc99e35456f Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Sat, 6 Jan 2024 19:37:47 +0200 Subject: [PATCH 080/112] add logcat viewer link to System settings --- AndroidManifest.xml | 1 + res/values/strings_ext.xml | 2 ++ res/xml/system_dashboard_fragment.xml | 7 ++++ .../system/LogcatLinkPrefController.java | 34 +++++++++++++++++++ 4 files changed, 44 insertions(+) create mode 100644 src/com/android/settings/system/LogcatLinkPrefController.java diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 666136f63c2..7b60bccb5af 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -148,6 +148,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 621a3253a83..6d335097b1a 100644 --- a/res/xml/system_dashboard_fragment.xml +++ b/res/xml/system_dashboard_fragment.xml @@ -84,6 +84,13 @@ + + Date: Sat, 2 Mar 2024 11:25:46 +0200 Subject: [PATCH 081/112] 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 74444f7c153..9ba367ab1ae 100644 --- a/src/com/android/settings/spa/app/appinfo/AppInfoSettings.kt +++ b/src/com/android/settings/spa/app/appinfo/AppInfoSettings.kt @@ -157,6 +157,7 @@ private fun AppInfoSettings(packageInfoPresenter: PackageInfoPresenter) { AppLocalePreference(app) AppOpenByDefaultPreference(app) DefaultAppShortcuts(app) + AppLogcatPreference(app) Category(title = stringResource(R.string.unused_apps_category)) { HibernationSwitchPreference(app, isHibernationSwitchEnabledStateFlow) 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 50ea9bcd89bd120b13d2048e37b0d23cc898b67e Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Wed, 21 Feb 2024 16:39:26 +0200 Subject: [PATCH 082/112] add USB-C port and pogo pins security setting --- res/values/strings_ext.xml | 32 ++++ res/xml/exploit_protection_settings.xml | 10 ++ .../UsbPortSecurityPrefController.java | 141 ++++++++++++++++++ 3 files changed, 183 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 e5d9f1455fe..caff1f7e903 100644 --- a/res/values/strings_ext.xml +++ b/res/values/strings_ext.xml @@ -143,4 +143,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 39d31713b9a..bdd4bf85656 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" /> + + + + (); + usbManager.setSecurityStateForAllPorts(state, new ResultReceiver(null) { + @Override + protected void onReceiveResult(int resultCode, Bundle resultData) { + if (resultCode != android.hardware.usb.ext.IUsbExt.NO_ERROR) { + String msg = "setPortSecurityState failed, " + + "resultCode: " + resultCode; + if (resultData != null) { + msg += ", resultData: " + resultData.toStringDeep(); + } + throw new RuntimeException(msg); + } + future.complete(null); + } + }); + try { + future.get(3, TimeUnit.SECONDS); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + private void setState(int prevSetting, @android.hardware.usb.ext.PortSecurityState int state) { + var usbManager = requireNonNull(mContext.getSystemService(UsbManager.class)); + if (prevSetting == UsbPortSecurity.MODE_CHARGING_ONLY && state >= UsbPortSecurity.MODE_CHARGING_ONLY_WHEN_LOCKED) { + // Turn USB ports off first to trigger reconnection of devices that were connected + // in charging-only state. Simply enabling the data path is not enough in some + // advanced scenarios, e.g. when port alt mode or port role switching are used. + setSecurityStateForAllPortsSync(usbManager, PortSecurityState.DISABLED); + } + setSecurityStateForAllPortsSync(usbManager, state); + } + + @Override + protected boolean setValue(int val) { + int prevSetting = getCurrentValue(); + boolean res = super.setValue(val); + if (!res) { + return false; + } + + int pss = switch (val) { + case UsbPortSecurity.MODE_DISABLED -> PortSecurityState.DISABLED; + case UsbPortSecurity.MODE_CHARGING_ONLY -> PortSecurityState.CHARGING_ONLY_IMMEDIATE; + case UsbPortSecurity.MODE_CHARGING_ONLY_WHEN_LOCKED -> PortSecurityState.ENABLED; + case UsbPortSecurity.MODE_CHARGING_ONLY_WHEN_LOCKED_AFU -> PortSecurityState.ENABLED; + case UsbPortSecurity.MODE_ENABLED -> PortSecurityState.ENABLED; + default -> throw new IllegalArgumentException(Integer.toString(val)); + }; + setState(prevSetting, pss); + return true; + } + + @Override + protected boolean isCredentialConfirmationRequired() { + return true; + } +} From 84e50e9586ef8b10cf39a9913fb0c4db542065dd Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Thu, 7 Mar 2024 12:21:53 +0200 Subject: [PATCH 083/112] 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 4b5d9526f16..acc67ecb639 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 1c710f0db690febf66fb43d1a448d98edbe07971 Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Sun, 17 Mar 2024 17:40:23 +0200 Subject: [PATCH 084/112] 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 bbc3e0a6675c114e9673e36f61f30b1c57c7dfa5 Mon Sep 17 00:00:00 2001 From: Jitesh Singh Date: Tue, 30 Jan 2024 19:48:12 +0530 Subject: [PATCH 085/112] 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 55735e66322..170d6998c36 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 69b32cf77aa44f3276984f14a2dca7baf0d0d552 Mon Sep 17 00:00:00 2001 From: Jitesh Singh Date: Wed, 31 Jan 2024 01:41:53 +0530 Subject: [PATCH 086/112] 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 7b60bccb5af..0b608e57ac7 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -515,6 +515,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"/> - - -