From 9e78b8c0843787260581fdb4d0b9cee5e1b22b25 Mon Sep 17 00:00:00 2001 From: Evan Chen Date: Wed, 14 Jun 2023 22:11:33 +0000 Subject: [PATCH 01/97] Make sure work profile app cant enable notification listener services Fix: 282934003 Test: Run test app in work profile (cherry picked from commit 81893c2b6f0743e7786ee133922c68834e3a4e16) (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:72f8ea55d38ab81524f54b666f8eebf3d4413f55) Merged-In: I7fed6d1baa1a40e9126493d37e33d63236bb4b3c Change-Id: I7fed6d1baa1a40e9126493d37e33d63236bb4b3c --- ...otificationAccessConfirmationActivity.java | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/com/android/settings/notification/NotificationAccessConfirmationActivity.java b/src/com/android/settings/notification/NotificationAccessConfirmationActivity.java index a6b565ae6ba..9ea8c58024f 100644 --- a/src/com/android/settings/notification/NotificationAccessConfirmationActivity.java +++ b/src/com/android/settings/notification/NotificationAccessConfirmationActivity.java @@ -17,6 +17,7 @@ package com.android.settings.notification; +import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_APPS_CANNOT_ACCESS_NOTIFICATION_SETTINGS; import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS; import static com.android.internal.notification.NotificationAccessConfirmationActivityContract.EXTRA_COMPONENT_NAME; @@ -26,6 +27,7 @@ import android.annotation.Nullable; import android.app.Activity; import android.app.NotificationManager; +import android.app.admin.DevicePolicyManager; import android.content.ComponentName; import android.content.Context; import android.content.DialogInterface; @@ -35,10 +37,12 @@ import android.content.pm.ServiceInfo; import android.os.Bundle; import android.os.UserHandle; +import android.os.UserManager; import android.text.TextUtils; import android.util.Slog; import android.view.WindowManager; import android.view.accessibility.AccessibilityEvent; +import android.widget.Toast; import com.android.internal.app.AlertActivity; import com.android.internal.app.AlertController; @@ -55,12 +59,28 @@ public class NotificationAccessConfirmationActivity extends Activity private ComponentName mComponentName; private NotificationManager mNm; + private DevicePolicyManager mDpm; + private UserManager mUm; + @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); getWindow().addSystemFlags(SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS); + mUm = getSystemService(UserManager.class); + mDpm = getSystemService(DevicePolicyManager.class); + + if (mUm.isManagedProfile()) { + Slog.w(LOG_TAG, "Apps in the work profile do not support notification listeners"); + Toast.makeText(this, + mDpm.getResources().getString(WORK_APPS_CANNOT_ACCESS_NOTIFICATION_SETTINGS, + () -> getString(R.string.notification_settings_work_profile)), + Toast.LENGTH_SHORT).show(); + finish(); + return; + } + mNm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); mComponentName = getIntent().getParcelableExtra(EXTRA_COMPONENT_NAME); From 2d6985bdbe979a2eecf18090adf2b3d1fd7c59dd Mon Sep 17 00:00:00 2001 From: Valentin Iftime Date: Tue, 3 Oct 2023 17:28:34 +0200 Subject: [PATCH 02/97] Validate ringtone URIs before setting Add checks URIs for content from other users. Fail for users that are not profiles of the current user. Test: atest DefaultRingtonePreferenceTest Bug: 299614635 (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:1876c449915c764242976280918758585689c82d) Merged-In: Ib266b285a3a1c6c5265ae2321159e61e08e349f6 Change-Id: Ib266b285a3a1c6c5265ae2321159e61e08e349f6 --- .../settings/DefaultRingtonePreference.java | 11 +-- .../android/settings/RingtonePreference.java | 83 +++++++++++++++++++ .../app/NotificationSoundPreference.java | 12 ++- .../DefaultRingtonePreferenceTest.java | 81 +++++++++++++++++- 4 files changed, 172 insertions(+), 15 deletions(-) diff --git a/src/com/android/settings/DefaultRingtonePreference.java b/src/com/android/settings/DefaultRingtonePreference.java index 9bf626c9898..4c654887227 100644 --- a/src/com/android/settings/DefaultRingtonePreference.java +++ b/src/com/android/settings/DefaultRingtonePreference.java @@ -51,16 +51,9 @@ protected void onSaveRingtone(Uri ringtoneUri) { return; } - String mimeType = mUserContext.getContentResolver().getType(ringtoneUri); - if (mimeType == null) { + if (!isValidRingtoneUri(ringtoneUri)) { Log.e(TAG, "onSaveRingtone for URI:" + ringtoneUri - + " ignored: failure to find mimeType (no access from this context?)"); - return; - } - - if (!(mimeType.startsWith("audio/") || mimeType.equals("application/ogg"))) { - Log.e(TAG, "onSaveRingtone for URI:" + ringtoneUri - + " ignored: associated mimeType:" + mimeType + " is not an audio type"); + + " ignored: invalid ringtone Uri"); return; } diff --git a/src/com/android/settings/RingtonePreference.java b/src/com/android/settings/RingtonePreference.java index 8f9c618d5e8..de5b7c39f76 100644 --- a/src/com/android/settings/RingtonePreference.java +++ b/src/com/android/settings/RingtonePreference.java @@ -16,6 +16,8 @@ package com.android.settings; +import android.content.ContentProvider; +import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.res.TypedArray; @@ -23,9 +25,11 @@ import android.media.RingtoneManager; import android.net.Uri; import android.os.UserHandle; +import android.os.UserManager; import android.provider.Settings.System; import android.text.TextUtils; import android.util.AttributeSet; +import android.util.Log; import androidx.preference.Preference; import androidx.preference.PreferenceManager; @@ -239,4 +243,83 @@ public boolean onActivityResult(int requestCode, int resultCode, Intent data) { return true; } + public boolean isDefaultRingtone(Uri ringtoneUri) { + // null URIs are valid (None/silence) + return ringtoneUri == null || RingtoneManager.isDefault(ringtoneUri); + } + + protected boolean isValidRingtoneUri(Uri ringtoneUri) { + if (isDefaultRingtone(ringtoneUri)) { + return true; + } + + // Return early for android resource URIs + if (ContentResolver.SCHEME_ANDROID_RESOURCE.equals(ringtoneUri.getScheme())) { + return true; + } + + String mimeType = mUserContext.getContentResolver().getType(ringtoneUri); + if (mimeType == null) { + Log.e(TAG, "isValidRingtoneUri for URI:" + ringtoneUri + + " failed: failure to find mimeType (no access from this context?)"); + return false; + } + + if (!(mimeType.startsWith("audio/") || mimeType.equals("application/ogg") + || mimeType.equals("application/x-flac"))) { + Log.e(TAG, "isValidRingtoneUri for URI:" + ringtoneUri + + " failed: associated mimeType:" + mimeType + " is not an audio type"); + return false; + } + + // Validate userId from URIs: content://{userId}@... + final int userIdFromUri = ContentProvider.getUserIdFromUri(ringtoneUri, mUserId); + if (userIdFromUri != mUserId) { + final UserManager userManager = mUserContext.getSystemService(UserManager.class); + + if (!userManager.isSameProfileGroup(mUserId, userIdFromUri)) { + Log.e(TAG, + "isValidRingtoneUri for URI:" + ringtoneUri + " failed: user " + userIdFromUri + + " and user " + mUserId + " are not in the same profile group"); + return false; + } + + final int parentUserId; + final int profileUserId; + if (userManager.isProfile()) { + profileUserId = mUserId; + parentUserId = userIdFromUri; + } else { + parentUserId = mUserId; + profileUserId = userIdFromUri; + } + + final UserHandle parent = userManager.getProfileParent(UserHandle.of(profileUserId)); + if (parent == null || parent.getIdentifier() != parentUserId) { + Log.e(TAG, + "isValidRingtoneUri for URI:" + ringtoneUri + " failed: user " + profileUserId + + " is not a profile of user " + parentUserId); + return false; + } + + // Allow parent <-> managed profile sharing, unless restricted + if (userManager.hasUserRestrictionForUser( + UserManager.DISALLOW_SHARE_INTO_MANAGED_PROFILE, UserHandle.of(parentUserId))) { + Log.e(TAG, + "isValidRingtoneUri for URI:" + ringtoneUri + " failed: user " + parentUserId + + " has restriction: " + UserManager.DISALLOW_SHARE_INTO_MANAGED_PROFILE); + return false; + } + + if (!(userManager.isManagedProfile(profileUserId) || userManager.getUserProperties( + UserHandle.of(profileUserId)).isMediaSharedWithParent())) { + Log.e(TAG, "isValidRingtoneUri for URI:" + ringtoneUri + + " failed: user " + profileUserId + " is not a cloned or managed profile"); + return false; + } + } + + return true; + } + } diff --git a/src/com/android/settings/notification/app/NotificationSoundPreference.java b/src/com/android/settings/notification/app/NotificationSoundPreference.java index 136b21ffd36..b55f9bd7ce8 100644 --- a/src/com/android/settings/notification/app/NotificationSoundPreference.java +++ b/src/com/android/settings/notification/app/NotificationSoundPreference.java @@ -25,10 +25,13 @@ import android.os.AsyncTask; import android.util.AttributeSet; +import android.util.Log; import com.android.settings.R; import com.android.settings.RingtonePreference; public class NotificationSoundPreference extends RingtonePreference { + private static final String TAG = "NotificationSoundPreference"; + private Uri mRingtone; public NotificationSoundPreference(Context context, AttributeSet attrs) { @@ -50,8 +53,13 @@ public void setRingtone(Uri ringtone) { public boolean onActivityResult(int requestCode, int resultCode, Intent data) { if (data != null) { Uri uri = data.getParcelableExtra(RingtoneManager.EXTRA_RINGTONE_PICKED_URI); - setRingtone(uri); - callChangeListener(uri); + if (isValidRingtoneUri(uri)) { + setRingtone(uri); + callChangeListener(uri); + } else { + Log.e(TAG, "onActivityResult for URI:" + uri + + " ignored: invalid ringtone Uri"); + } } return true; diff --git a/tests/unit/src/com/android/settings/DefaultRingtonePreferenceTest.java b/tests/unit/src/com/android/settings/DefaultRingtonePreferenceTest.java index 7877684dce6..c580fc58145 100644 --- a/tests/unit/src/com/android/settings/DefaultRingtonePreferenceTest.java +++ b/tests/unit/src/com/android/settings/DefaultRingtonePreferenceTest.java @@ -16,16 +16,20 @@ package com.android.settings; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import android.content.ContentInterface; import android.content.ContentResolver; import android.content.Context; -import android.media.RingtoneManager; +import android.content.pm.UserProperties; import android.net.Uri; +import android.os.UserHandle; +import android.os.UserManager; import androidx.test.core.app.ApplicationProvider; import androidx.test.ext.junit.runners.AndroidJUnit4; @@ -34,17 +38,22 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; +import org.mockito.Mockito; import org.mockito.MockitoAnnotations; /** Unittest for DefaultRingtonePreference. */ @RunWith(AndroidJUnit4.class) public class DefaultRingtonePreferenceTest { + private static final int OWNER_USER_ID = 1; + private static final int OTHER_USER_ID = 10; + private static final int INVALID_RINGTONE_TYPE = 0; private DefaultRingtonePreference mDefaultRingtonePreference; @Mock private ContentResolver mContentResolver; @Mock + private UserManager mUserManager; private Uri mRingtoneUri; @Before @@ -52,14 +61,29 @@ public void setUp() { MockitoAnnotations.initMocks(this); Context context = spy(ApplicationProvider.getApplicationContext()); - doReturn(mContentResolver).when(context).getContentResolver(); + mContentResolver = ContentResolver.wrap(Mockito.mock(ContentInterface.class)); + when(context.getContentResolver()).thenReturn(mContentResolver); mDefaultRingtonePreference = spy(new DefaultRingtonePreference(context, null /* attrs */)); doReturn(context).when(mDefaultRingtonePreference).getContext(); + + // Use INVALID_RINGTONE_TYPE to return early in RingtoneManager.setActualDefaultRingtoneUri when(mDefaultRingtonePreference.getRingtoneType()) - .thenReturn(RingtoneManager.TYPE_RINGTONE); - mDefaultRingtonePreference.setUserId(1); + .thenReturn(INVALID_RINGTONE_TYPE); + + mDefaultRingtonePreference.setUserId(OWNER_USER_ID); mDefaultRingtonePreference.mUserContext = context; + when(mDefaultRingtonePreference.isDefaultRingtone(any(Uri.class))).thenReturn(false); + + when(context.getSystemServiceName(UserManager.class)).thenReturn(Context.USER_SERVICE); + when(context.getSystemService(Context.USER_SERVICE)).thenReturn(mUserManager); + + UserProperties userProperties = new UserProperties.Builder().setMediaSharedWithParent(false) + .build(); + when(mUserManager.getUserProperties(UserHandle.of(OTHER_USER_ID))).thenReturn( + userProperties); + + mRingtoneUri = Uri.parse("content://none"); } @Test @@ -79,4 +103,53 @@ public void onSaveRingtone_notAudioMimeType_shouldNotSetRingtone() { verify(mDefaultRingtonePreference, never()).setActualDefaultRingtoneUri(mRingtoneUri); } + + @Test + public void onSaveRingtone_notManagedProfile_shouldNotSetRingtone() { + mRingtoneUri = Uri.parse("content://" + OTHER_USER_ID + "@ringtone"); + when(mContentResolver.getType(mRingtoneUri)).thenReturn("audio/*"); + when(mUserManager.isSameProfileGroup(OWNER_USER_ID, OTHER_USER_ID)).thenReturn(true); + when(mUserManager.getProfileParent(UserHandle.of(OTHER_USER_ID))).thenReturn( + UserHandle.of(OWNER_USER_ID)); + when(mUserManager.isManagedProfile(OTHER_USER_ID)).thenReturn(false); + + mDefaultRingtonePreference.onSaveRingtone(mRingtoneUri); + + verify(mDefaultRingtonePreference, never()).setActualDefaultRingtoneUri(mRingtoneUri); + } + + @Test + public void onSaveRingtone_notSameUser_shouldNotSetRingtone() { + mRingtoneUri = Uri.parse("content://" + OTHER_USER_ID + "@ringtone"); + when(mContentResolver.getType(mRingtoneUri)).thenReturn("audio/*"); + when(mUserManager.isSameProfileGroup(OWNER_USER_ID, OTHER_USER_ID)).thenReturn(false); + + mDefaultRingtonePreference.onSaveRingtone(mRingtoneUri); + + verify(mDefaultRingtonePreference, never()).setActualDefaultRingtoneUri(mRingtoneUri); + } + + @Test + public void onSaveRingtone_isManagedProfile_shouldSetRingtone() { + mRingtoneUri = Uri.parse("content://" + OTHER_USER_ID + "@ringtone"); + when(mContentResolver.getType(mRingtoneUri)).thenReturn("audio/*"); + when(mUserManager.isSameProfileGroup(OWNER_USER_ID, OTHER_USER_ID)).thenReturn(true); + when(mUserManager.getProfileParent(UserHandle.of(OTHER_USER_ID))).thenReturn( + UserHandle.of(OWNER_USER_ID)); + when(mUserManager.isManagedProfile(OTHER_USER_ID)).thenReturn(true); + + mDefaultRingtonePreference.onSaveRingtone(mRingtoneUri); + + verify(mDefaultRingtonePreference).setActualDefaultRingtoneUri(mRingtoneUri); + } + + @Test + public void onSaveRingtone_defaultUri_shouldSetRingtone() { + mRingtoneUri = Uri.parse("default_ringtone"); + when(mDefaultRingtonePreference.isDefaultRingtone(any(Uri.class))).thenReturn(true); + + mDefaultRingtonePreference.onSaveRingtone(mRingtoneUri); + + verify(mDefaultRingtonePreference).setActualDefaultRingtoneUri(mRingtoneUri); + } } From 13c5a54b55b148cfc354afe6b344ecd7863e4c19 Mon Sep 17 00:00:00 2001 From: flawedworld Date: Sat, 5 Feb 2022 17:42:07 +0000 Subject: [PATCH 03/97] 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 453a71e1ad0..64f42a71bdc 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -137,7 +137,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 98ffbe83b5b1abce0c1b8b3e25319b4ab8692010 Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Fri, 14 Oct 2022 21:08:02 -0400 Subject: [PATCH 04/97] 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 17c33989502..5cb7b5b193d 100755 --- a/res/values/config.xml +++ b/res/values/config.xml @@ -47,9 +47,9 @@ - + android.intent.action.MAIN - + android.intent.action.MAIN com.android.wallpaper.LAUNCH_SOURCE From 454ccc8dd6c5ef17110f729ecb637dce35a210eb Mon Sep 17 00:00:00 2001 From: Danny Lin Date: Sat, 17 Apr 2021 15:15:51 +0100 Subject: [PATCH 05/97] 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 5cb7b5b193d..af9984d3285 100755 --- a/res/values/config.xml +++ b/res/values/config.xml @@ -42,10 +42,10 @@ com.android.settings.overlay.FeatureFactoryImpl - 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 9f866c4d97345ec9848d0170aec8a75c5f92a78a Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Tue, 16 Feb 2021 02:22:41 -0500 Subject: [PATCH 06/97] 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 af9984d3285..d53b69be3ab 100755 --- a/res/values/config.xml +++ b/res/values/config.xml @@ -460,7 +460,7 @@ true - true + false true From 42a39ff5be43c4bfa2c8e83e3fb979985a11084f Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Wed, 10 Mar 2021 00:45:12 -0500 Subject: [PATCH 07/97] 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 d53b69be3ab..c7a84151832 100755 --- a/res/values/config.xml +++ b/res/values/config.xml @@ -75,6 +75,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 d4b04e3705ce4c2d999bd40e2faee366eadd5509 Mon Sep 17 00:00:00 2001 From: inthewaves Date: Sun, 20 Sep 2020 17:57:30 -0700 Subject: [PATCH 08/97] 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 9eb5418087b8211cdadd7e0bce8c0a2e5cdc74f1 Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Tue, 8 Oct 2019 08:11:55 -0400 Subject: [PATCH 09/97] 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 c7a84151832..70091998e15 100755 --- a/res/values/config.xml +++ b/res/values/config.xml @@ -234,7 +234,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 4cc19186514210fe7f2594041d51f72f6536a20a Mon Sep 17 00:00:00 2001 From: Renlord Date: Sat, 11 Apr 2020 20:04:51 +1000 Subject: [PATCH 10/97] 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 d050a1f2747..ebae388688f 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 11/97] 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 12/97] do not allow disabling the bundled keyboard --- .../settings/applications/ApplicationFeatureProviderImpl.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/com/android/settings/applications/ApplicationFeatureProviderImpl.java b/src/com/android/settings/applications/ApplicationFeatureProviderImpl.java index 80d39475931..08a08fea03b 100644 --- a/src/com/android/settings/applications/ApplicationFeatureProviderImpl.java +++ b/src/com/android/settings/applications/ApplicationFeatureProviderImpl.java @@ -183,6 +183,10 @@ private Set getEnabledPackageAllowlist() { if (mPm.getWellbeingPackageName() != null) { keepEnabledPackages.add(mPm.getWellbeingPackageName()); } + + // Bundled keyboard, needed for text input in Direct Boot mode if the selected 3rd party + // keyboard doesn't support it + keepEnabledPackages.add("com.android.inputmethod.latin"); return keepEnabledPackages; } From 95f0a52a96b437e2ffe6f35001d8c8dbedac28af Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Sun, 28 May 2023 18:43:14 +0300 Subject: [PATCH 13/97] do not allow disabling Vanadium WebView --- .../settings/applications/ApplicationFeatureProviderImpl.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/com/android/settings/applications/ApplicationFeatureProviderImpl.java b/src/com/android/settings/applications/ApplicationFeatureProviderImpl.java index 08a08fea03b..12e2b02fac6 100644 --- a/src/com/android/settings/applications/ApplicationFeatureProviderImpl.java +++ b/src/com/android/settings/applications/ApplicationFeatureProviderImpl.java @@ -187,6 +187,9 @@ private Set getEnabledPackageAllowlist() { // Bundled keyboard, needed for text input in Direct Boot mode if the selected 3rd party // keyboard doesn't support it keepEnabledPackages.add("com.android.inputmethod.latin"); + + // Replacing WebView is not supported + keepEnabledPackages.add("app.vanadium.webview"); return keepEnabledPackages; } From d1332835870bffbfac857bf57da2e2ac805aec05 Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Sun, 28 May 2023 18:43:42 +0300 Subject: [PATCH 14/97] do not allow disabling GrapheneOS Camera --- .../settings/applications/ApplicationFeatureProviderImpl.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/com/android/settings/applications/ApplicationFeatureProviderImpl.java b/src/com/android/settings/applications/ApplicationFeatureProviderImpl.java index 12e2b02fac6..24b9ae1c80d 100644 --- a/src/com/android/settings/applications/ApplicationFeatureProviderImpl.java +++ b/src/com/android/settings/applications/ApplicationFeatureProviderImpl.java @@ -190,6 +190,9 @@ private Set getEnabledPackageAllowlist() { // Replacing WebView is not supported keepEnabledPackages.add("app.vanadium.webview"); + + // Only bundled camera can handle some of camera intents + keepEnabledPackages.add("app.grapheneos.camera"); return keepEnabledPackages; } From 2f5fc7649b574acb7f44027975088f72843a93ba Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Sun, 28 May 2023 18:44:08 +0300 Subject: [PATCH 15/97] do not allow disabling GmsCompat and GmsCompatConfig --- .../applications/ApplicationFeatureProviderImpl.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/com/android/settings/applications/ApplicationFeatureProviderImpl.java b/src/com/android/settings/applications/ApplicationFeatureProviderImpl.java index 24b9ae1c80d..11459fe32e1 100644 --- a/src/com/android/settings/applications/ApplicationFeatureProviderImpl.java +++ b/src/com/android/settings/applications/ApplicationFeatureProviderImpl.java @@ -193,6 +193,11 @@ private Set getEnabledPackageAllowlist() { // Only bundled camera can handle some of camera intents keepEnabledPackages.add("app.grapheneos.camera"); + + // Disabling GmsCompat app breaks the gmscompat layer + keepEnabledPackages.add(com.android.internal.gmscompat.GmsCompatApp.PKG_NAME); + // Disabling GmsCompatConfig breaks updates through Apps app + keepEnabledPackages.add(com.android.internal.gmscompat.GmsCompatApp.PKG_NAME + ".config"); return keepEnabledPackages; } From 808afd5e97f0b364ba9077b1bb35cd3500c7a15a Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Sun, 28 May 2023 18:44:30 +0300 Subject: [PATCH 16/97] do not allow disabling EuiccSupportPixel --- .../applications/ApplicationFeatureProviderImpl.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/com/android/settings/applications/ApplicationFeatureProviderImpl.java b/src/com/android/settings/applications/ApplicationFeatureProviderImpl.java index 11459fe32e1..e0bc44f3ec3 100644 --- a/src/com/android/settings/applications/ApplicationFeatureProviderImpl.java +++ b/src/com/android/settings/applications/ApplicationFeatureProviderImpl.java @@ -40,6 +40,7 @@ import androidx.annotation.VisibleForTesting; import com.android.internal.telephony.SmsApplication; +import com.android.internal.util.GoogleEuicc; import com.android.settings.R; import java.util.ArrayList; @@ -198,6 +199,10 @@ private Set getEnabledPackageAllowlist() { keepEnabledPackages.add(com.android.internal.gmscompat.GmsCompatApp.PKG_NAME); // Disabling GmsCompatConfig breaks updates through Apps app keepEnabledPackages.add(com.android.internal.gmscompat.GmsCompatApp.PKG_NAME + ".config"); + + // EuiccSupportPixel handles firmware updates of embedded secure element that is used for eSIM, NFC, Felica etc + keepEnabledPackages.add(GoogleEuicc.EUICC_SUPPORT_PIXEL_PKG_NAME); + return keepEnabledPackages; } From a1b0be573f5c1fa22afc65503954336fe8fcabf6 Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Sun, 12 Feb 2023 20:21:09 +0200 Subject: [PATCH 17/97] 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 c39abb351dddd68cd47188bed36b217c19a93984 Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Thu, 6 Apr 2023 12:06:11 +0300 Subject: [PATCH 18/97] add a set of base classes for creating Fragment-based preference UI --- res/values/strings_ext.xml | 4 +- .../settings/ext/BoolSettingFragment.java | 149 ++++++++++++++++++ .../BoolSettingFragmentPrefController.java | 26 +++ .../ext/ExtSettingFragmentPrefController.java | 42 +++++ .../settings/ext/FragmentPrefController.java | 36 +++++ 5 files changed, 256 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..12aac5fc4ad --- /dev/null +++ b/src/com/android/settings/ext/BoolSettingFragment.java @@ -0,0 +1,149 @@ +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.SwitchPreference; + +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 SwitchPreference 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 SwitchPreference(ctx); + mainSwitch.setTitle(getMainSwitchTitle()); + + this.mainSwitch = mainSwitch; + refreshMainSwitch(); + + mainSwitch.setOnPreferenceChangeListener((preference, newValue) -> { + boolean state = (boolean) newValue; + + if (invertSetting) { + state = !state; + } + + 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 void onMainSwitchChanged(boolean state) {} + + private 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 066f8b8c410f7f1728bf7866c14eedd809d9d6c9 Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Sun, 12 Feb 2023 19:43:44 +0200 Subject: [PATCH 19/97] add base class for ListPreference controllers --- .../ext/AbstractListPreferenceController.java | 235 ++++++++++++++++++ .../ext/RadioButtonPickerFragment2.java | 117 +++++++++ .../widget/RadioButtonPickerFragment.java | 16 +- 3 files changed, 364 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..342ffeef5df --- /dev/null +++ b/src/com/android/settings/ext/AbstractListPreferenceController.java @@ -0,0 +1,235 @@ +/* + * 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); + } +} diff --git a/src/com/android/settings/ext/RadioButtonPickerFragment2.java b/src/com/android/settings/ext/RadioButtonPickerFragment2.java new file mode 100644 index 00000000000..f6e8b91486c --- /dev/null +++ b/src/com/android/settings/ext/RadioButtonPickerFragment2.java @@ -0,0 +1,117 @@ +package com.android.settings.ext; + +import android.content.Context; +import android.os.Bundle; + +import androidx.preference.Preference; +import androidx.preference.PreferenceScreen; + +import com.android.settings.core.BasePreferenceController; +import com.android.settings.utils.CandidateInfoExtra; +import com.android.settings.widget.RadioButtonPickerFragment; +import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; +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); + } + + @Override + public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { + PreferenceScreen ps = getPreferenceManager().createPreferenceScreen(requireContext()); + setPreferenceScreen(ps); + } + + @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) { + 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); + } + + @Override + public void onResume() { + super.onResume(); + prefController.onResume(this); + updateCandidates(); + } +} diff --git a/src/com/android/settings/widget/RadioButtonPickerFragment.java b/src/com/android/settings/widget/RadioButtonPickerFragment.java index 9450bb93715..2cedbdaf42c 100644 --- a/src/com/android/settings/widget/RadioButtonPickerFragment.java +++ b/src/com/android/settings/widget/RadioButtonPickerFragment.java @@ -53,7 +53,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; @@ -157,6 +157,12 @@ public void bindPreferenceExtra(SelectorWithWidgetPreference pref, String key, CandidateInfo info, String defaultKey, String systemDefaultKey) { } + protected void addPrefsBeforeList(PreferenceScreen screen) { + if (!mAppendStaticPreferences) { + addStaticPreferences(screen); + } + } + public void updateCandidates() { mCandidates.clear(); final List candidateList = getCandidates(); @@ -172,9 +178,7 @@ public void updateCandidates() { if (mIllustrationId != 0) { addIllustration(screen); } - if (!mAppendStaticPreferences) { - addStaticPreferences(screen); - } + addPrefsBeforeList(screen); final int customLayoutResId = getRadioButtonPreferenceCustomLayoutResId(); if (shouldShowItemNone()) { @@ -202,6 +206,10 @@ public void updateCandidates() { } } mayCheckOnlyRadioButton(); + addPrefsAfterList(screen); + } + + protected void addPrefsAfterList(PreferenceScreen screen) { if (mAppendStaticPreferences) { addStaticPreferences(screen); } From 40ec33b8a5e2adac2aef769e3c3bba729a0b551d Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Tue, 14 Feb 2023 08:45:56 +0200 Subject: [PATCH 20/97] 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 4875776413987fa9a1b7c79bba222aba8bc766c9 Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Sun, 12 Feb 2023 19:44:07 +0200 Subject: [PATCH 21/97] add base classes for {Bool,Int}Setting preference controllers If no customization is needed, BoolSetting base class can be used directly from XML by adding settings:boolSettingField=" " to the preference XML definition. --- res/values/attrs.xml | 2 + .../core/PreferenceControllerListHelper.java | 3 + .../core/PreferenceXmlParserUtils.java | 12 +++ .../ext/BoolSettingPrefController.java | 90 +++++++++++++++++++ .../ext/ExtSettingControllerHelper.java | 69 ++++++++++++++ .../ext/ExtSettingPrefController.java | 12 +++ .../ext/IntSettingPrefController.java | 57 ++++++++++++ 7 files changed, 245 insertions(+) create mode 100644 src/com/android/settings/ext/BoolSettingPrefController.java create mode 100644 src/com/android/settings/ext/ExtSettingControllerHelper.java create mode 100644 src/com/android/settings/ext/ExtSettingPrefController.java create mode 100644 src/com/android/settings/ext/IntSettingPrefController.java diff --git a/res/values/attrs.xml b/res/values/attrs.xml index 6f024a32be3..0a778da8894 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 6d450fe137f..18e67982583 100644 --- a/src/com/android/settings/core/PreferenceControllerListHelper.java +++ b/src/com/android/settings/core/PreferenceControllerListHelper.java @@ -28,6 +28,7 @@ import android.util.Log; import com.android.settings.core.PreferenceXmlParserUtils.MetadataFlag; +import com.android.settings.ext.BoolSettingPrefController; import com.android.settingslib.core.AbstractPreferenceController; import org.xmlpull.v1.XmlPullParserException; @@ -56,6 +57,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); @@ -65,6 +67,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 a1a8d6731a7..d9a1c397b64 100644 --- a/src/com/android/settings/core/PreferenceXmlParserUtils.java +++ b/src/com/android/settings/core/PreferenceXmlParserUtils.java @@ -68,6 +68,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_UNAVAILABLE_SLICE_SUBTITLE = 1 << 11; int FLAG_FOR_WORK = 1 << 12; int FLAG_NEED_HIGHLIGHTABLE_MENU_KEY = 1 << 13; + + 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"; @@ -225,6 +229,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)); } @@ -321,6 +329,10 @@ private static String getController(TypedArray styledAttributes) { return styledAttributes.getString(R.styleable.Preference_controller); } + private static String getBoolSettingField(TypedArray styledAttributes) { + return styledAttributes.getString(R.styleable.Preference_boolSettingField); + } + private static String getHighlightableMenuKey(TypedArray styledAttributes) { return styledAttributes.getString(R.styleable.Preference_highlightableMenuKey); } diff --git a/src/com/android/settings/ext/BoolSettingPrefController.java b/src/com/android/settings/ext/BoolSettingPrefController.java new file mode 100644 index 00000000000..2d6d668cfc2 --- /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 final 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..46ad5cfeecf --- /dev/null +++ b/src/com/android/settings/ext/ExtSettingControllerHelper.java @@ -0,0 +1,69 @@ +/* + * 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.os.Process; +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 Process.myUserHandle().isSystem() ? AVAILABLE : DISABLED_FOR_USER; + } + + 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, settingObserver, context.getMainThreadHandler()); + } + } + + 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..53f3bf810b9 --- /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 final 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 381d1fb7c6d4a1fd03a4b4da96457a3e4a04f7b4 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 22/97] 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 7fe1daa5cba..2bfb0697f19 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -2688,6 +2688,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 23/97] 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 a5172dbc0450f2bc28fde31a857a96fe371d8f5c Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Sun, 25 Jul 2021 14:44:48 -0400 Subject: [PATCH 24/97] 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 70091998e15..17ffc8b1a7f 100755 --- a/res/values/config.xml +++ b/res/values/config.xml @@ -500,7 +500,7 @@ false - content://com.google.android.gms.nearby.fastpair/device_status_list_item + From 857e173e31779d3c0beb4da0e5e3711b4f895cba Mon Sep 17 00:00:00 2001 From: Your Name Date: Mon, 18 Oct 2021 02:17:56 +0000 Subject: [PATCH 25/97] 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 22bc23f7201d68db81e3a23c3fc012d109ca76fd Mon Sep 17 00:00:00 2001 From: Danny Lin Date: Wed, 7 Jul 2021 03:02:05 -0700 Subject: [PATCH 26/97] 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 2bfb0697f19..3f364841ea8 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -2430,6 +2430,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 c5e559cd8a7..514dcba967d 100644 --- a/res/xml/display_settings.xml +++ b/res/xml/display_settings.xml @@ -144,6 +144,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 27/97] add link to Sandboxed Google Play settings add Sandboxed Google Play link for the work profile The link is now dynamic and becomes hidden if GMS Core is uninstalled or disabled. --- res/values/strings.xml | 5 ++ res/xml/apps.xml | 13 ++++ .../applications/GmsCompatAppController.java | 65 +++++++++++++++++++ 3 files changed, 83 insertions(+) create mode 100644 src/com/android/settings/applications/GmsCompatAppController.java diff --git a/res/values/strings.xml b/res/values/strings.xml index 3f364841ea8..627104f09fc 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -12316,4 +12316,9 @@ "This app can only be opened in 1 window" + Allow fingerprint unlocking + Allow fingerprints to unlock the screen lock. If this is disabled, fingerprints can still be used in apps. + + Sandboxed Google Play + Sandboxed Google Play (work profile) diff --git a/res/xml/apps.xml b/res/xml/apps.xml index c4313f645e4..440ad50b6ec 100644 --- a/res/xml/apps.xml +++ b/res/xml/apps.xml @@ -126,4 +126,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..ff8232d3601 --- /dev/null +++ b/src/com/android/settings/applications/GmsCompatAppController.java @@ -0,0 +1,65 @@ +/* + * 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.applications; + +import android.app.compat.gms.GmsCompat; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +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 { + private final Context context; + + public GmsCompatAppController(Context context, String key) { + super(context, key); + this.context = context; + } + + @Override + public int getAvailabilityStatus() { + UserHandle workProfile = getWorkProfileUser(); + int userId = workProfile != null ? + workProfile.getIdentifier() : + UserHandle.myUserId(); + + return GmsCompat.isGmsApp(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) { + context.startActivityAsUser(intent, workProfile); + } else { + context.startActivity(intent); + } + return true; + } +} From da5b05456309724676665bbf91c4524e09606d09 Mon Sep 17 00:00:00 2001 From: flawedworld Date: Sat, 5 Mar 2022 17:37:47 +0000 Subject: [PATCH 28/97] 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 f249f7fa627..e46c85a4b25 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 7d4ed4b8bf0c02d01768a41753f70b519cd2cb7c Mon Sep 17 00:00:00 2001 From: Chirayu Desai Date: Tue, 3 Mar 2020 18:45:32 +0530 Subject: [PATCH 29/97] Remove empty Security status header Change-Id: Ia09dfd67bcfb8334439bfb9dab419235b182e297 --- res/xml/security_dashboard_settings.xml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/res/xml/security_dashboard_settings.xml b/res/xml/security_dashboard_settings.xml index 0550441d3f2..211ff997d1e 100644 --- a/res/xml/security_dashboard_settings.xml +++ b/res/xml/security_dashboard_settings.xml @@ -21,12 +21,6 @@ android:key="security_dashboard_page" android:title="@string/security_settings_title"> - - - From 448af0d730ea0d91402dc71372dca8e9284d7c52 Mon Sep 17 00:00:00 2001 From: Roman Royer Date: Wed, 4 May 2016 19:04:36 -0700 Subject: [PATCH 30/97] 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 d734a27f033..27dbd80be73 100644 --- a/src/com/android/settings/applications/manageapplications/ManageApplications.java +++ b/src/com/android/settings/applications/manageapplications/ManageApplications.java @@ -850,9 +850,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 755960b87079d26ab8c7ed60cc3912cbf07cbdaf Mon Sep 17 00:00:00 2001 From: empratyush Date: Wed, 4 May 2022 20:54:16 +0530 Subject: [PATCH 31/97] 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 bea0c3389ec..155d540b6cd 100644 --- a/src/com/android/settings/biometrics/face/FaceEnrollIntroduction.java +++ b/src/com/android/settings/biometrics/face/FaceEnrollIntroduction.java @@ -357,32 +357,32 @@ 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 R.string.security_settings_face_enroll_introduction_info_looking; + return 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 16be004001eb1a896564109e35abc63d84a6c29e Mon Sep 17 00:00:00 2001 From: June Date: Wed, 16 Mar 2022 07:09:46 +0200 Subject: [PATCH 32/97] 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 9055a0e64c7..f064381b136 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -12331,6 +12331,9 @@ Allow fingerprint unlocking Allow fingerprints to unlock the screen lock. If this is disabled, fingerprints can still be used in apps. + 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..6c7ac2c091a 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 b0816fdf4ad..018a267cdcf 100644 --- a/src/com/android/settings/users/UserSettings.java +++ b/src/com/android/settings/users/UserSettings.java @@ -137,6 +137,8 @@ public class UserSettings extends SettingsPreferenceFragment private static final String KEY_REMOVE_GUEST_ON_EXIT = "remove_guest_on_exit"; 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_SEND_CENSORED_NOTIFICATIONS = + "user_settings_send_censored_notifications_to_current"; private static final String SETTING_GUEST_HAS_LOGGED_IN = "systemui.guest_has_logged_in"; @@ -225,6 +227,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; @@ -322,6 +325,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); @@ -332,11 +339,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() { mTimeoutToDockUserPreferenceController.getPreferenceKey())); mRemoveGuestOnExitPreferenceController.updateState(screen.findPreference( mRemoveGuestOnExitPreferenceController.getPreferenceKey())); + mSendCensoredNotificationsToCurrentUserPreferenceController.updateState(screen.findPreference( + mSendCensoredNotificationsToCurrentUserPreferenceController.getPreferenceKey())); + if (mShouldUpdateUserList) { updateUI(); } @@ -1303,6 +1316,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); @@ -1744,6 +1761,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 9a5dc1e0c2b79c81757dc3c57ce052a2bd09a737 Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Wed, 17 Aug 2022 12:40:26 -0400 Subject: [PATCH 33/97] 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 61682d00a8c..6b28d921efa 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 @@ -85,9 +85,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 d6586673f89..abda482a1e5 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 b887eb10c4b1cb77e7e6560060f35b935d0451c9 Mon Sep 17 00:00:00 2001 From: renlord Date: Fri, 15 Oct 2021 20:02:51 +0530 Subject: [PATCH 34/97] add option to always randomize MAC RANDOMIZATION_ALWAYS is set as the default option --- res/layout/wifi_network_config.xml | 2 +- res/values/arrays.xml | 7 +++++ res/xml/wifi_network_details_fragment2.xml | 2 +- .../WifiDetailPreferenceController2.java | 2 +- .../WifiPrivacyPreferenceController2.java | 28 +++++++++++++++---- 5 files changed, 32 insertions(+), 9 deletions(-) diff --git a/res/layout/wifi_network_config.xml b/res/layout/wifi_network_config.xml index 6fe39bf0261..7752f70532b 100644 --- a/res/layout/wifi_network_config.xml +++ b/res/layout/wifi_network_config.xml @@ -693,7 +693,7 @@ android:layout_height="wrap_content" style="@style/wifi_item_spinner" android:prompt="@string/wifi_privacy_settings" - android:entries="@array/wifi_privacy_entries"/> + android:entries="@array/wifi_privacy_entries_extended"/> Treat as unmetered + + Use per-connection randomized MAC (default) + Use per-network randomized MAC + Use device MAC + + Use randomized MAC (default) Use device MAC @@ -1076,6 +1082,7 @@ + 100 1 0 diff --git a/res/xml/wifi_network_details_fragment2.xml b/res/xml/wifi_network_details_fragment2.xml index 00624749377..88b245adc49 100644 --- a/res/xml/wifi_network_details_fragment2.xml +++ b/res/xml/wifi_network_details_fragment2.xml @@ -94,7 +94,7 @@ android:key="privacy" android:icon="@drawable/ic_wifi_privacy_24dp" android:title="@string/wifi_privacy_settings" - android:entries="@array/wifi_privacy_entries" + android:entries="@array/wifi_privacy_entries_extended" android:entryValues="@array/wifi_privacy_values"/> Date: Fri, 19 Aug 2022 11:05:36 +0530 Subject: [PATCH 35/97] 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 f064381b136..18d9d56c8f7 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -10799,6 +10799,8 @@ Preferred network mode: CDMA/EvDo/GSM/WCDMA Preferred network mode: LTE + + Preferred network mode: LTE only Preferred network mode: GSM/WCDMA/LTE @@ -10864,8 +10866,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 9fb80a5d412..3d7d6a85ab6 100644 --- a/src/com/android/settings/network/telephony/EnabledNetworkModePreferenceController.java +++ b/src/com/android/settings/network/telephony/EnabledNetworkModePreferenceController.java @@ -91,7 +91,7 @@ public int getAvailabilityStatus(int subId) { CarrierConfigManager.KEY_HIDE_CARRIER_NETWORK_SETTINGS_BOOL) || carrierConfig.getBoolean( CarrierConfigManager.KEY_HIDE_PREFERRED_NETWORK_TYPE_BOOL)) { - visible = false; + visible = true; } else if (carrierConfig.getBoolean(CarrierConfigManager.KEY_WORLD_PHONE_BOOL)) { visible = false; } else if (!isCallStateIdle()) { @@ -276,6 +276,7 @@ public void updateConfig() { } void setPreferenceEntries() { + boolean lteOnlyUnsupported = false; mTelephonyManager = mTelephonyManager.createForSubscriptionId(mSubId); clearAllEntries(); @@ -291,6 +292,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) @@ -310,6 +312,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); @@ -327,6 +330,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) @@ -375,6 +379,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)) { @@ -561,6 +570,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( @@ -826,6 +838,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 bdfeace1be6..535645a8647 100644 --- a/src/com/android/settings/network/telephony/PreferredNetworkModePreferenceController.java +++ b/src/com/android/settings/network/telephony/PreferredNetworkModePreferenceController.java @@ -137,7 +137,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 fd7ab8e3eb892aa7702cc5fde31d69a930c90eb6 Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Sun, 13 Nov 2022 20:24:05 +0200 Subject: [PATCH 36/97] battery usage UI: use a fallback name for unknown components --- .../settings/fuelgauge/batteryusage/BatteryEntry.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryEntry.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryEntry.java index 86538ee8811..f0e157525e0 100644 --- a/src/com/android/settings/fuelgauge/batteryusage/BatteryEntry.java +++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryEntry.java @@ -572,9 +572,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 519524b0a4f047645a3b6d818b8b860fcfe8e570 Mon Sep 17 00:00:00 2001 From: LuK1337 Date: Thu, 9 Jun 2022 11:27:32 +0200 Subject: [PATCH 37/97] 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 f4d7607c85e..37a502895ae 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 38/97] add a toggle for auto-grants of OTHER_SENSORS permission --- res/values/strings_ext.xml | 4 ++++ res/xml/privacy_dashboard_settings.xml | 7 +++++++ 2 files changed, 11 insertions(+) diff --git a/res/values/strings_ext.xml b/res/values/strings_ext.xml index e46c85a4b25..5777e48d296 100644 --- a/res/values/strings_ext.xml +++ b/res/values/strings_ext.xml @@ -6,4 +6,8 @@ Enabled Disabled + 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/privacy_dashboard_settings.xml b/res/xml/privacy_dashboard_settings.xml index d84dca536b8..4553010cdc9 100644 --- a/res/xml/privacy_dashboard_settings.xml +++ b/res/xml/privacy_dashboard_settings.xml @@ -85,6 +85,13 @@ android:summary="@string/mic_toggle_description" settings:controller="com.android.settings.privacy.MicToggleController"/> + + Date: Tue, 14 Feb 2023 10:27:56 +0200 Subject: [PATCH 39/97] add a toggle for camera access from the lock screen --- res/values/strings_ext.xml | 2 ++ res/xml/security_dashboard_settings.xml | 8 +++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/res/values/strings_ext.xml b/res/values/strings_ext.xml index 5777e48d296..76ed86af267 100644 --- a/res/values/strings_ext.xml +++ b/res/values/strings_ext.xml @@ -10,4 +10,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 the device is locked + diff --git a/res/xml/security_dashboard_settings.xml b/res/xml/security_dashboard_settings.xml index 211ff997d1e..dcd82af2ae5 100644 --- a/res/xml/security_dashboard_settings.xml +++ b/res/xml/security_dashboard_settings.xml @@ -49,6 +49,12 @@ android:summary="@string/summary_placeholder" settings:keywords="@string/keywords_face_settings" /> + + - \ No newline at end of file + From 855f113bbb7ff462f457b9ff1c138a27319221e5 Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Tue, 14 Feb 2023 11:23:29 +0200 Subject: [PATCH 40/97] add auto-reboot setting Squashed with: 20d4d3e46ba4a626d6044df499b91c1fc5e5bd96 514f0ddf2adbb7b69b0750806020476cef8ed17e Co-authored-by: Daniel Micay --- res/values/strings_ext.xml | 3 ++ res/xml/security_dashboard_settings.xml | 5 +++ .../security/AutoRebootPrefController.java | 44 +++++++++++++++++++ 3 files changed, 52 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 76ed86af267..c0fdec85619 100644 --- a/res/values/strings_ext.xml +++ b/res/values/strings_ext.xml @@ -12,4 +12,7 @@ Allow camera access when the device is locked + Auto reboot + Automatically reboot the device if it hasn\'t been unlocked within the selected duration of time. + diff --git a/res/xml/security_dashboard_settings.xml b/res/xml/security_dashboard_settings.xml index dcd82af2ae5..0b88f619819 100644 --- a/res/xml/security_dashboard_settings.xml +++ b/res/xml/security_dashboard_settings.xml @@ -49,6 +49,11 @@ android:summary="@string/summary_placeholder" settings:keywords="@string/keywords_face_settings" /> + + Date: Sat, 18 Feb 2023 11:09:31 -0500 Subject: [PATCH 41/97] Add toggle for screenshot timestamp EXIF metadata Signed-off-by: r3g_5z --- res/values/strings_ext.xml | 3 +++ res/xml/privacy_dashboard_settings.xml | 7 +++++++ 2 files changed, 10 insertions(+) diff --git a/res/values/strings_ext.xml b/res/values/strings_ext.xml index c0fdec85619..29819695086 100644 --- a/res/values/strings_ext.xml +++ b/res/values/strings_ext.xml @@ -15,4 +15,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/privacy_dashboard_settings.xml b/res/xml/privacy_dashboard_settings.xml index 4553010cdc9..ece8fab41a2 100644 --- a/res/xml/privacy_dashboard_settings.xml +++ b/res/xml/privacy_dashboard_settings.xml @@ -92,6 +92,13 @@ 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 42/97] add GNSS SUPL setting --- res/values/strings_ext.xml | 8 +++++ res/xml/location_settings.xml | 5 ++++ .../location/GnssSuplPrefController.java | 30 +++++++++++++++++++ 3 files changed, 43 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 29819695086..bd2a571bbca 100644 --- a/res/values/strings_ext.xml +++ b/res/values/strings_ext.xml @@ -18,4 +18,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. + + Enabled (GrapheneOS proxy) + Enabled (standard server) + Disabled + Will make acquiring location lock significantly slower, especially if PSDS is disabled too + diff --git a/res/xml/location_settings.xml b/res/xml/location_settings.xml index fe87efd73d7..7f9f45378c3 100644 --- a/res/xml/location_settings.xml +++ b/res/xml/location_settings.xml @@ -66,6 +66,11 @@ android:title="@string/location_services_preference_title" settings:controller="com.android.settings.location.LocationServicesPreferenceController"/> + + Date: Sat, 18 Feb 2023 10:08:21 -0500 Subject: [PATCH 43/97] add PIN scrambling setting Signed-off-by: r3g_5z --- res/values/strings_ext.xml | 2 ++ res/xml/security_dashboard_settings.xml | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/res/values/strings_ext.xml b/res/values/strings_ext.xml index bd2a571bbca..a05671e2577 100644 --- a/res/values/strings_ext.xml +++ b/res/values/strings_ext.xml @@ -26,4 +26,6 @@ Disabled Will make acquiring location lock significantly slower, especially if PSDS is disabled too + Scramble PIN input layout + diff --git a/res/xml/security_dashboard_settings.xml b/res/xml/security_dashboard_settings.xml index 0b88f619819..43f880c07c5 100644 --- a/res/xml/security_dashboard_settings.xml +++ b/res/xml/security_dashboard_settings.xml @@ -54,6 +54,11 @@ android:title="@string/auto_reboot_title" settings:controller="com.android.settings.security.AutoRebootPrefController" /> + + Date: Mon, 16 Oct 2023 09:42:40 -0400 Subject: [PATCH 44/97] 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 ed155bcb10c..29988582a5e 100644 --- a/src/com/android/settings/password/ChooseLockPassword.java +++ b/src/com/android/settings/password/ChooseLockPassword.java @@ -976,9 +976,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 9a1df7074d830674e57effd0d85ef971c5084645 Mon Sep 17 00:00:00 2001 From: r3g_5z Date: Wed, 15 Mar 2023 21:11:12 -0400 Subject: [PATCH 45/97] 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 daf1793f11f..9954efb1dca 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()); @@ -222,7 +221,6 @@ protected boolean setDefaultKey(final String key) { } setDisplayMode(width); - updateIllustrationImage(mImagePreference); return true; } From 90df840e6cee8b20f2467b787746e2a3a2c07aab Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Sat, 19 Mar 2022 12:01:00 +0200 Subject: [PATCH 46/97] add toggle for the privileged eSIM management --- res/values/strings_ext.xml | 6 + res/xml/network_provider_internet.xml | 9 + .../network/GoogleEuiccLpaController.java | 174 ++++++++++++++++++ 3 files changed, 189 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 a05671e2577..2ce08456abf 100644 --- a/res/values/strings_ext.xml +++ b/res/values/strings_ext.xml @@ -28,4 +28,10 @@ Scramble PIN input layout + Enable privileged eSIM management + Requires sandboxed Google Play installation + Device restart is required to disable this setting. + Restart + Device restart is required to allow enabling this setting. + diff --git a/res/xml/network_provider_internet.xml b/res/xml/network_provider_internet.xml index ef6ed16f73f..7cf29452cf8 100644 --- a/res/xml/network_provider_internet.xml +++ b/res/xml/network_provider_internet.xml @@ -55,6 +55,15 @@ settings:useAdminDisabledSummary="true" settings:searchable="@bool/config_show_sim_info"/> + + { + var pm = mContext.getSystemService(PowerManager.class); + pm.reboot(null); + }); + b.show(); + return false; + } + + if (!GoogleEuicc.checkLpaDependencies()) { + // this is a race condition, toggle hasn't been grayed out yet + return false; + } + + ContentResolver cr = mContext.getContentResolver(); + + if (Settings.Global.getInt(cr, Settings.Global.BOOT_COUNT, 0) == 1) { + // When BOOT_COUNT is 1, Google's LPA assumes that it was started together with Google's + // SetupWizard, and changes its behavior in unwanted ways. + // + // To avoid this, require a reboot, which will increment BOOT_COUNT + + var b = new AlertDialog.Builder(mContext); + b.setMessage(R.string.privileged_euicc_management_restart_due_to_first_boot); + b.setPositiveButton(R.string.privileged_euicc_management_restart_button, (dialogInterface, btn) -> { + var pm = mContext.getSystemService(PowerManager.class); + pm.reboot(null); + }); + b.show(); + return false; + } + + PermissionManager permissionManager = mContext.getSystemService(PermissionManager.class); + + try { + String pkg = GoogleEuicc.LPA_PKG_NAME; + + UserHandle user = mContext.getUser(); + String perm = Manifest.permission.CAMERA; + permissionManager.revokeRuntimePermission(pkg, perm, user, null); + // Previously, Camera permission was auto-granted with the FLAG_PERMISSION_SYSTEM_FIXED, + // which made it unchangeable by the user. + // Removing FLAG_PERMISSION_USER_FIXED is needed to make sure that the app is always + // able to show a permission request dialog after being enabled + int permFlagsToRemove = PackageManager.FLAG_PERMISSION_SYSTEM_FIXED + | PackageManager.FLAG_PERMISSION_USER_FIXED; + permissionManager.updatePermissionFlags(pkg, perm, permFlagsToRemove, 0, user); + + packageManager.setApplicationEnabledSetting(pkg, COMPONENT_ENABLED_STATE_ENABLED, 0); + { + // Google's LPA expects to be enabled at boot, when ACTION_LOCKED_BOOT_COMPLETED + // is normally sent. + // Upon receiving this broadcast, it performs additional initialization that is + // skipped otherwise, see RestoreUiccSlotSettingsOnBootReceiver and CompleteBootService + var intent = new Intent(Intent.ACTION_LOCKED_BOOT_COMPLETED); + intent.setPackage(pkg); + mContext.sendBroadcast(intent); + } + return true; + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + private final BroadcastReceiver packageChangeListener = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (preference != null) { + updateState(preference); + } + } + }; + + @Override + public void onResume(@NonNull LifecycleOwner owner) { + var f = new IntentFilter(); + f.addAction(Intent.ACTION_PACKAGE_ADDED); + f.addAction(Intent.ACTION_PACKAGE_CHANGED); + f.addAction(Intent.ACTION_PACKAGE_REMOVED); + f.addAction(Intent.ACTION_PACKAGE_FULLY_REMOVED); + + f.addDataScheme("package"); + for (String pkg : GoogleEuicc.getLpaDependencies()) { + f.addDataSchemeSpecificPart(pkg, PatternMatcher.PATTERN_LITERAL); + } + + f.addDataSchemeSpecificPart(GoogleEuicc.LPA_PKG_NAME, PatternMatcher.PATTERN_LITERAL); + + mContext.registerReceiver(packageChangeListener, f); + } + + @Override + public void onPause(@NonNull LifecycleOwner owner) { + mContext.unregisterReceiver(packageChangeListener); + } +} From b6bd24d499479157c0e0ef82b7ebdb5a155442f3 Mon Sep 17 00:00:00 2001 From: r3g_5z Date: Sun, 2 Apr 2023 22:23:41 -0400 Subject: [PATCH 47/97] 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 | 37 +++++++++++++++++++ 3 files changed, 48 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 2ce08456abf..ef3330acfd9 100644 --- a/res/values/strings_ext.xml +++ b/res/values/strings_ext.xml @@ -34,4 +34,9 @@ Restart Device restart is required to allow enabling this setting. + Attestation key provisioning + Enabled (GrapheneOS proxy) + Enabled (Google server) + Disabled + diff --git a/res/xml/network_provider_internet.xml b/res/xml/network_provider_internet.xml index 7cf29452cf8..65e61eb71dc 100644 --- a/res/xml/network_provider_internet.xml +++ b/res/xml/network_provider_internet.xml @@ -138,4 +138,10 @@ android:summary="@string/summary_placeholder" android:order="25" settings:controller="com.android.settings.network.AdaptiveConnectivityPreferenceController"/> + + diff --git a/src/com/android/settings/network/RemoteProvisioningPrefController.java b/src/com/android/settings/network/RemoteProvisioningPrefController.java new file mode 100644 index 00000000000..64155249c91 --- /dev/null +++ b/src/com/android/settings/network/RemoteProvisioningPrefController.java @@ -0,0 +1,37 @@ +/* + * 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.ExtSettings; +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, ExtSettings.REMOTE_KEY_PROVISIONING_SERVER); + } + + @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 3b2d623dd18263d508b7aafbdb3989e60a3fb33a Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Thu, 6 Apr 2023 12:11:09 +0300 Subject: [PATCH 48/97] 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 ef3330acfd9..b8d5bb7cd7e 100644 --- a/res/values/strings_ext.xml +++ b/res/values/strings_ext.xml @@ -39,4 +39,19 @@ Enabled (Google server) Disabled + 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 b3f3f7dd5da..f890a6b7000 100644 --- a/res/xml/special_access.xml +++ b/res/xml/special_access.xml @@ -219,4 +219,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 3e80066e5d37c1d9a933aaf2ab1623bb2b23f89a Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Wed, 3 May 2023 08:57:01 +0300 Subject: [PATCH 49/97] add GNSS PSDS setting --- res/values/strings_ext.xml | 11 ++++ res/xml/location_settings.xml | 5 ++ .../location/GnssPsdsPrefController.java | 52 +++++++++++++++++++ 3 files changed, 68 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 b8d5bb7cd7e..500217f6929 100644 --- a/res/values/strings_ext.xml +++ b/res/values/strings_ext.xml @@ -54,4 +54,15 @@ Examples of such apps: This setting applies to all users on the device." + Predicted Satellite Data Service (PSDS) + +"If PSDS is enabled, 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." + + Enabled (GrapheneOS server) + Enabled (Qualcomm server) + Enabled (standard server) + Disabled + Will make acquiring location lock significantly slower, especially if SUPL is disabled too + diff --git a/res/xml/location_settings.xml b/res/xml/location_settings.xml index 7f9f45378c3..eff9d20af55 100644 --- a/res/xml/location_settings.xml +++ b/res/xml/location_settings.xml @@ -71,6 +71,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 50/97] add connectivity checks setting --- res/values/strings_ext.xml | 10 +++++++ res/xml/network_provider_internet.xml | 6 ++++ .../ConnectivityChecksPrefController.java | 30 +++++++++++++++++++ 3 files changed, 46 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 500217f6929..3731b82f6de 100644 --- a/res/values/strings_ext.xml +++ b/res/values/strings_ext.xml @@ -65,4 +65,14 @@ No query or data is sent to the server. These files contain orbits and statuses Disabled Will make acquiring location lock significantly slower, especially if SUPL is disabled too + GrapheneOS server + Standard (Google) server + Disabled + + 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 65e61eb71dc..825e0f98b80 100644 --- a/res/xml/network_provider_internet.xml +++ b/res/xml/network_provider_internet.xml @@ -139,6 +139,12 @@ android:order="25" settings:controller="com.android.settings.network.AdaptiveConnectivityPreferenceController"/> + + Date: Wed, 24 May 2023 14:57:01 +0300 Subject: [PATCH 51/97] 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 3731b82f6de..8366d62f67a 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 697a9bef5a01fab78b01dd81659fcf3ba9b61aba Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Thu, 25 May 2023 16:25:33 +0300 Subject: [PATCH 52/97] add Wi-Fi auto-off setting --- res/values/strings_ext.xml | 2 + res/xml/wifi_configure_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 8366d62f67a..fade43178e6 100644 --- a/res/values/strings_ext.xml +++ b/res/values/strings_ext.xml @@ -76,4 +76,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/wifi_configure_settings.xml b/res/xml/wifi_configure_settings.xml index 2ab7b6a28fe..d8833ef3216 100644 --- a/res/xml/wifi_configure_settings.xml +++ b/res/xml/wifi_configure_settings.xml @@ -34,6 +34,11 @@ settings:keywords="@string/keywords_wifi_notify_open_networks" settings:controller="com.android.settings.wifi.NotifyOpenNetworksPreferenceController"/> + + Date: Wed, 24 May 2023 15:01:04 +0300 Subject: [PATCH 53/97] add Bluetooth auto-off setting --- res/values/strings_ext.xml | 6 +++ res/xml/bluetooth_screen.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 fade43178e6..b973136e3f7 100644 --- a/res/values/strings_ext.xml +++ b/res/values/strings_ext.xml @@ -78,4 +78,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/bluetooth_screen.xml b/res/xml/bluetooth_screen.xml index 86dc8a12c72..fa7f59e3b91 100644 --- a/res/xml/bluetooth_screen.xml +++ b/res/xml/bluetooth_screen.xml @@ -36,6 +36,11 @@ settings:searchable="false" settings:controller="com.android.settings.connecteddevice.AddDevicePreferenceController"/> + + Date: Wed, 24 May 2023 18:23:22 +0300 Subject: [PATCH 54/97] add deny_new_usb setting --- res/values/strings_ext.xml | 7 ++ res/xml/security_dashboard_settings.xml | 5 ++ .../security/DenyNewUsbPrefController.java | 77 +++++++++++++++++++ 3 files changed, 89 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 b973136e3f7..38cfff9be3c 100644 --- a/res/values/strings_ext.xml +++ b/res/values/strings_ext.xml @@ -84,4 +84,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/security_dashboard_settings.xml b/res/xml/security_dashboard_settings.xml index 43f880c07c5..208cc6d08f6 100644 --- a/res/xml/security_dashboard_settings.xml +++ b/res/xml/security_dashboard_settings.xml @@ -54,6 +54,11 @@ android:title="@string/auto_reboot_title" settings:controller="com.android.settings.security.AutoRebootPrefController" /> + + list = Arrays.asList( + DENY_NEW_USB_DISABLED, + DENY_NEW_USB_DYNAMIC, + DENY_NEW_USB_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(DENY_NEW_USB_ENABLED)); + entries.add(R.string.deny_new_usb_val_dynamic, list.indexOf(DENY_NEW_USB_DYNAMIC)); + entries.add(R.string.deny_new_usb_val_disabled, list.indexOf(DENY_NEW_USB_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(ExtSettings.DENY_NEW_USB.get()); + } + + @Override + protected boolean setValue(int val) { + String strVal = list.get(val); + boolean res = ExtSettings.DENY_NEW_USB.put(strVal); + if (!res) { + return false; + } + if (DENY_NEW_USB_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(ExtSettings.DENY_NEW_USB_TRANSIENT_PROP, + ExtSettings.DENY_NEW_USB_TRANSIENT_DISABLE); + } + return true; + } +} From c4cd17cb584f37e96556797dadf64383342f8507 Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Thu, 25 May 2023 16:47:42 +0300 Subject: [PATCH 55/97] add exec spawning setting --- res/values/strings_ext.xml | 4 +++ res/xml/security_dashboard_settings.xml | 6 ++++ .../security/ExecSpawningFragment.java | 34 +++++++++++++++++++ .../security/ExecSpawningPrefController.java | 13 +++++++ 4 files changed, 57 insertions(+) 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 38cfff9be3c..5a0ece12f97 100644 --- a/res/values/strings_ext.xml +++ b/res/values/strings_ext.xml @@ -91,4 +91,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/security_dashboard_settings.xml b/res/xml/security_dashboard_settings.xml index 208cc6d08f6..07dc3aa714b 100644 --- a/res/xml/security_dashboard_settings.xml +++ b/res/xml/security_dashboard_settings.xml @@ -59,6 +59,12 @@ android:title="@string/deny_new_usb_title" settings:controller="com.android.settings.security.DenyNewUsbPrefController" /> + + Date: Sun, 25 Jun 2023 13:53:58 +0100 Subject: [PATCH 56/97] 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 5d0f5347f402ec47498a169cca5bd4154dd1a230 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 57/97] Remove "Add users from lock screen" setting --- .../users/AddUserWhenLockedPreferenceController.java | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/com/android/settings/users/AddUserWhenLockedPreferenceController.java b/src/com/android/settings/users/AddUserWhenLockedPreferenceController.java index ce5533e5c64..0983648d47d 100644 --- a/src/com/android/settings/users/AddUserWhenLockedPreferenceController.java +++ b/src/com/android/settings/users/AddUserWhenLockedPreferenceController.java @@ -50,13 +50,7 @@ public void updateState(Preference preference) { @Override public int getAvailabilityStatus() { - if (!mUserCaps.isAdmin()) { - return DISABLED_FOR_USER; - } else if (mUserCaps.disallowAddUser() || mUserCaps.disallowAddUserSetByAdmin()) { - return DISABLED_FOR_USER; - } else { - return mUserCaps.mUserSwitcherEnabled ? AVAILABLE : CONDITIONALLY_UNAVAILABLE; - } + return UNSUPPORTED_ON_DEVICE; } @Override From bebf81ddadca8b4fdf6de9a8478f3c973808dcb4 Mon Sep 17 00:00:00 2001 From: Pratyush Date: Sat, 3 Sep 2022 15:52:37 +0530 Subject: [PATCH 58/97] 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 402d4b18dd4..fe6bd8d6e0a 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; @@ -403,7 +403,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 025f11ada6eb9f22f74d9cd97ef8af7731544c17 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 59/97] Factor out common code for reading/writing UserManager restrictions --- .../settings/users/UserDetailsSettings.java | 11 +++-- .../settings/users/UserRestrictions.java | 49 +++++++++++++++++++ 2 files changed, 55 insertions(+), 5 deletions(-) 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 fe6bd8d6e0a..91d36934e93 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() { @@ -340,6 +341,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); @@ -388,6 +390,7 @@ void initialize(Context context, Bundle arguments) { removePreference(KEY_APP_AND_CONTENT_ACCESS); } + mPhonePref.setChecked(!userRestrictions.isSet(UserManager.DISALLOW_OUTGOING_CALLS)); if (mUserInfo.isGuest()) { removePreference(KEY_ENABLE_TELEPHONY); mRemoveUserPref.setTitle(mGuestUserAutoCreated @@ -400,8 +403,6 @@ void initialize(Context context, Bundle arguments) { removePreference(KEY_APP_COPYING); } } else { - mPhonePref.setChecked(!mUserManager.hasUserRestriction( - UserManager.DISALLOW_OUTGOING_CALLS, new UserHandle(userId))); mRemoveUserPref.setTitle(R.string.user_remove_user); } @@ -473,9 +474,9 @@ void switchUser() { private void enableCallsAndSms(boolean enabled) { mPhonePref.setChecked(enabled); - UserHandle userHandle = UserHandle.of(mUserInfo.id); - mUserManager.setUserRestriction(UserManager.DISALLOW_OUTGOING_CALLS, !enabled, userHandle); - mUserManager.setUserRestriction(UserManager.DISALLOW_SMS, !enabled, userHandle); + userRestrictions.set(UserManager.DISALLOW_OUTGOING_CALLS, !enabled); + // SMS is always disabled for guest + userRestrictions.set(UserManager.DISALLOW_SMS, mUserInfo.isGuest() || !enabled); } /** diff --git a/src/com/android/settings/users/UserRestrictions.java b/src/com/android/settings/users/UserRestrictions.java new file mode 100644 index 00000000000..3daa2c453dc --- /dev/null +++ b/src/com/android/settings/users/UserRestrictions.java @@ -0,0 +1,49 @@ +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) { + Bundle defaultGuestRestrictions = userManager.getDefaultGuestRestrictions(); + if (userInfo.isGuest()) { + defaultGuestRestrictions.putBoolean(restrictionKey, enableRestriction); + userManager.setDefaultGuestRestrictions(defaultGuestRestrictions); + + List users = userManager.getAliveUsers(); + for (UserInfo user : users) { + if (user.isGuest()) { + UserHandle userHandle = userInfo.getUserHandle(); + for (String key : defaultGuestRestrictions.keySet()) { + userManager.setUserRestriction( + key, defaultGuestRestrictions.getBoolean(key), userHandle); + } + } + } + } else { + userManager.setUserRestriction(restrictionKey, enableRestriction, userInfo.getUserHandle()); + } + } +} From ad645c29f7c98d5c225c9e66c6d9e144bd4abbe6 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 60/97] 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 5a0ece12f97..76525a3cd3c 100644 --- a/res/values/strings_ext.xml +++ b/res/values/strings_ext.xml @@ -95,4 +95,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 068039cbd04..5ce43027662 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 91d36934e93..5f9187f7182 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 SwitchPreference mGrantAdminPref; + Preference mAppsInstallsPref; @VisibleForTesting /** The user being studied (not the user doing the studying). */ @@ -131,6 +134,8 @@ public void onResume() { if (mGuestUserAutoCreated) { mRemoveUserPref.setEnabled((mUserInfo.flags & UserInfo.FLAG_INITIALIZED) != 0); } + mAppsInstallsPref.setSummary(UserAppsInstallSettings.getDescription( + requireContext(), userRestrictions)); } @Override @@ -171,6 +176,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; } @@ -351,6 +359,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, @@ -374,6 +383,7 @@ void initialize(Context context, Bundle arguments) { removePreference(KEY_GRANT_ADMIN); 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); @@ -415,6 +425,7 @@ void initialize(Context context, Bundle arguments) { } mRemoveUserPref.setOnPreferenceClickListener(this); + mAppsInstallsPref.setOnPreferenceClickListener(this); mPhonePref.setOnPreferenceChangeListener(this); mGrantAdminPref.setOnPreferenceChangeListener(this); mAppAndContentAccessPref.setOnPreferenceClickListener(this); From e76ec6ef62f0ab4684495a58227bbdf79b5791e1 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 61/97] UserManager settings for running in background --- res/values/strings_ext.xml | 2 ++ res/xml/user_details_settings.xml | 4 ++++ .../android/settings/users/UserDetailsSettings.java | 12 ++++++++++++ 3 files changed, 18 insertions(+) diff --git a/res/values/strings_ext.xml b/res/values/strings_ext.xml index 76525a3cd3c..1108deabaa0 100644 --- a/res/values/strings_ext.xml +++ b/res/values/strings_ext.xml @@ -105,5 +105,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 5ce43027662..e2aa90cfdad 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 62/97] 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 4b449b01945..86685839971 100644 --- a/src/com/android/settings/users/UserDetailsSettings.java +++ b/src/com/android/settings/users/UserDetailsSettings.java @@ -138,6 +138,7 @@ public void onResume() { } mAppsInstallsPref.setSummary(UserAppsInstallSettings.getDescription( requireContext(), userRestrictions)); + mAppCopyingPref.setEnabled(!userRestrictions.isSet(UserManager.DISALLOW_INSTALL_APPS)); } @Override From 45c613bb684cdbbe73fe00afb4f5c2af45c16aec Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Mon, 15 May 2023 15:41:39 +0300 Subject: [PATCH 63/97] add a base class for extra "App info" screen links --- .../ext/AppInfoPreferenceControllerBase2.java | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 src/com/android/settings/ext/AppInfoPreferenceControllerBase2.java diff --git a/src/com/android/settings/ext/AppInfoPreferenceControllerBase2.java b/src/com/android/settings/ext/AppInfoPreferenceControllerBase2.java new file mode 100644 index 00000000000..d0794d13925 --- /dev/null +++ b/src/com/android/settings/ext/AppInfoPreferenceControllerBase2.java @@ -0,0 +1,37 @@ +package com.android.settings.ext; + +import android.content.Context; +import android.content.pm.GosPackageState; +import android.text.TextUtils; + +import androidx.preference.Preference; + +import com.android.settings.applications.appinfo.AppInfoPreferenceControllerBase; + +public abstract class AppInfoPreferenceControllerBase2 extends AppInfoPreferenceControllerBase { + + protected AppInfoPreferenceControllerBase2(Context ctx, String key) { + super(ctx, key); + } + + @Override + public boolean handlePreferenceTreeClick(Preference preference) { + if (!TextUtils.equals(preference.getKey(), getPreferenceKey())) { + return false; + } + + onPreferenceClick(getPackageName()); + return true; + } + + public abstract void onPreferenceClick(String packageName); + + protected boolean hasGosPackageStateFlags(int flags) { + var ps = GosPackageState.get(getPackageName()); + return ps != null && ps.hasFlags(flags); + } + + protected String getPackageName() { + return mParent.getPackageInfo().packageName; + } +} From 8167ee599ce1a41dab22f2ced0b0d841ba557370 Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Sat, 2 Jul 2022 09:41:50 +0300 Subject: [PATCH 64/97] add Storage Scopes link to the "App info" screen --- res/values/strings.xml | 2 ++ res/xml/app_info_settings.xml | 5 ++++ .../appinfo/AppInfoDashboardFragment.java | 1 + .../AppStorageScopesPreferenceController.java | 24 +++++++++++++++++++ 4 files changed, 32 insertions(+) create mode 100644 src/com/android/settings/applications/appinfo/AppStorageScopesPreferenceController.java diff --git a/res/values/strings.xml b/res/values/strings.xml index 18d9d56c8f7..50ac0755985 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -12342,4 +12342,6 @@ Sandboxed Google Play Sandboxed Google Play (work profile) + + Storage Scopes diff --git a/res/xml/app_info_settings.xml b/res/xml/app_info_settings.xml index 73241b705f4..53d5678a323 100644 --- a/res/xml/app_info_settings.xml +++ b/res/xml/app_info_settings.xml @@ -59,6 +59,11 @@ settings:summaryLineCount="1" settings:controller="com.android.settings.applications.appinfo.AppPermissionPreferenceController" /> + + Date: Tue, 11 Apr 2023 17:59:17 +0300 Subject: [PATCH 65/97] add Storage Scopes link to "All files access" screen --- .../appinfo/ManageExternalStorageDetails.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/com/android/settings/applications/appinfo/ManageExternalStorageDetails.java b/src/com/android/settings/applications/appinfo/ManageExternalStorageDetails.java index 6c840d5d94d..517f75ff5c1 100644 --- a/src/com/android/settings/applications/appinfo/ManageExternalStorageDetails.java +++ b/src/com/android/settings/applications/appinfo/ManageExternalStorageDetails.java @@ -16,6 +16,7 @@ package com.android.settings.applications.appinfo; import android.app.AppOpsManager; +import android.app.StorageScope; import android.app.settings.SettingsEnums; import android.content.Context; import android.os.Bundle; @@ -68,6 +69,8 @@ public void onCreate(Bundle savedInstanceState) { mMetricsFeatureProvider = FeatureFactory.getFactory(getContext()).getMetricsFeatureProvider(); + + addStorageScopesLink(); } @Override @@ -176,4 +179,11 @@ private static CharSequence getSummary(Context context, PermissionState state) { ? R.string.app_permission_summary_allowed : R.string.app_permission_summary_not_allowed); } + + private void addStorageScopesLink() { + Preference p = new Preference(requireContext()); + p.setTitle(R.string.storage_scopes); + p.setIntent(StorageScope.createConfigActivityIntent(mPackageName)); + getPreferenceScreen().addPreference(p); + } } From 8be748b9fc0190840bde6f33e23e571ca559ffc6 Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Fri, 8 Jul 2022 13:40:22 +0300 Subject: [PATCH 66/97] add OBB access toggle to "Install unknown apps" screen --- res/values/strings.xml | 3 + .../appinfo/ExternalSourcesDetails.java | 55 +++++++++++++++++++ 2 files changed, 58 insertions(+) diff --git a/res/values/strings.xml b/res/values/strings.xml index 50ac0755985..5ebcbf682e7 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -12344,4 +12344,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/applications/appinfo/ExternalSourcesDetails.java b/src/com/android/settings/applications/appinfo/ExternalSourcesDetails.java index b7232744365..f1ab2820520 100644 --- a/src/com/android/settings/applications/appinfo/ExternalSourcesDetails.java +++ b/src/com/android/settings/applications/appinfo/ExternalSourcesDetails.java @@ -21,6 +21,7 @@ import android.app.AppOpsManager; import android.app.settings.SettingsEnums; import android.content.Context; +import android.content.pm.GosPackageState; import android.os.Bundle; import android.os.UserHandle; import android.os.UserManager; @@ -133,6 +134,9 @@ protected boolean refreshUi() { return true; } mSwitchPref.setChecked(mInstallAppsState.canInstallApps()); + + setupObbToggle(); + return true; } @@ -145,4 +149,55 @@ protected AlertDialog createDialog(int id, int errorCode) { public int getMetricsCategory() { return SettingsEnums.MANAGE_EXTERNAL_SOURCES; } + + private RestrictedSwitchPreference mObbPref; + + private void setupObbToggle() { + RestrictedSwitchPreference p = mObbPref; + if (p == null) { + if (!GosPackageState.attachableToPackage(mPackageName)) { + return; + } + p = createObbToggle(); + mSwitchPref.getParent().addPreference(p); + mObbPref = p; + } + + boolean canInstallApps = mInstallAppsState.canInstallApps(); + + if (!canInstallApps) { + p.setChecked(false); + p.callChangeListener(Boolean.FALSE); + } else { + GosPackageState ps = GosPackageState.get(mPackageName); + p.setChecked(ps != null && ps.hasFlag(GosPackageState.FLAG_ALLOW_ACCESS_TO_OBB_DIRECTORY)); + } + + p.setEnabled(canInstallApps); + } + + private RestrictedSwitchPreference createObbToggle() { + RestrictedSwitchPreference p = new RestrictedSwitchPreference(mSwitchPref.getContext()); + p.setTitle(R.string.allow_access_to_obb_directory_title); + p.setSummary(R.string.allow_access_to_obb_directory_summary); + + p.setOnPreferenceChangeListener((preference, checkedB) -> { + var ps = GosPackageState.get(mPackageName); + boolean curValue = ps != null && ps.hasFlag(GosPackageState.FLAG_ALLOW_ACCESS_TO_OBB_DIRECTORY); + + if (curValue == (boolean) checkedB) { + return true; + } + + GosPackageState.edit(mPackageName) + .setFlagsState(GosPackageState.FLAG_ALLOW_ACCESS_TO_OBB_DIRECTORY, (boolean) checkedB) + // storage mount modes can't be updated dynamically + .killUidAfterApply() + .apply(); + + return true; + }); + + return p; + } } From fd7433ddc448e6dc9417051a0bee10f607f99be0 Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Wed, 21 Sep 2022 19:23:25 +0300 Subject: [PATCH 67/97] show more APK details on App info screen --- res/values/strings.xml | 3 ++ .../AppVersionPreferenceController.java | 40 ++++++++++++++++++- 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/res/values/strings.xml b/res/values/strings.xml index 5ebcbf682e7..a722a9aca54 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -12347,4 +12347,7 @@ Allow access to Android/obb folder Required for installation of some large apps (mostly games) that use OBB expansion files + + Installed: %1$s + Updated: %1$s diff --git a/src/com/android/settings/applications/appinfo/AppVersionPreferenceController.java b/src/com/android/settings/applications/appinfo/AppVersionPreferenceController.java index 23dd9602f77..734bd6ff476 100644 --- a/src/com/android/settings/applications/appinfo/AppVersionPreferenceController.java +++ b/src/com/android/settings/applications/appinfo/AppVersionPreferenceController.java @@ -22,6 +22,9 @@ import com.android.settings.R; +import java.text.DateFormat; +import java.util.Date; + public class AppVersionPreferenceController extends AppInfoPreferenceControllerBase { public AppVersionPreferenceController(Context context, String key) { @@ -36,7 +39,40 @@ public CharSequence getSummary() { if (packageInfo == null) { return null; } - return mContext.getString(R.string.version_text, - BidiFormatter.getInstance().unicodeWrap(packageInfo.versionName)); + + Context ctx = mContext; + + DateFormat dateFormat = android.text.format.DateFormat.getMediumDateFormat(ctx); + DateFormat timeFormat = android.text.format.DateFormat.getTimeFormat(ctx); + + String times = null; + if (packageInfo.firstInstallTime != 0) { + String s = formatDate(packageInfo.firstInstallTime, dateFormat, timeFormat); + times = ctx.getString(R.string.app_info_install_time, s); + } + + if (packageInfo.lastUpdateTime != 0 && packageInfo.lastUpdateTime != packageInfo.firstInstallTime) { + String s = formatDate(packageInfo.lastUpdateTime, dateFormat, timeFormat); + String updateTime = ctx.getString(R.string.app_info_update_time, s); + if (times != null) { + times += '\n' + updateTime; + } else { + times = updateTime; + } + } + + return ctx.getString(R.string.version_text, + BidiFormatter.getInstance().unicodeWrap(packageInfo.versionName)) + + "\n\n" + packageInfo.packageName + + "\nversionCode " + packageInfo.getLongVersionCode() + + "\n\ntargetSdk " + packageInfo.applicationInfo.targetSdkVersion + + "\nminSdk " + packageInfo.applicationInfo.minSdkVersion + + (times != null ? ("\n\n" + times) : "") + ; + } + + private static String formatDate(long unixTs, DateFormat dateFormat, DateFormat timeFormat) { + Date d = new Date(unixTs); + return dateFormat.format(d) + "; " + timeFormat.format(d); } } From 1b8c163b768b72bcdbe2c0a7a7bcde45a1376494 Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Mon, 15 May 2023 15:42:11 +0300 Subject: [PATCH 68/97] add Contact Scopes link to the "App info" screen --- res/values/strings_ext.xml | 2 ++ res/xml/app_info_settings.xml | 6 +++++ .../AppContactScopesPreferenceController.java | 24 +++++++++++++++++++ .../appinfo/AppInfoDashboardFragment.java | 1 + 4 files changed, 33 insertions(+) create mode 100644 src/com/android/settings/applications/appinfo/AppContactScopesPreferenceController.java diff --git a/res/values/strings_ext.xml b/res/values/strings_ext.xml index 1108deabaa0..cdb541a627e 100644 --- a/res/values/strings_ext.xml +++ b/res/values/strings_ext.xml @@ -66,6 +66,8 @@ No query or data is sent to the server. These files contain orbits and statuses Disabled Will make acquiring location lock significantly slower, especially if SUPL is disabled too + Contact Scopes + GrapheneOS server Standard (Google) server Disabled diff --git a/res/xml/app_info_settings.xml b/res/xml/app_info_settings.xml index 53d5678a323..628f9722265 100644 --- a/res/xml/app_info_settings.xml +++ b/res/xml/app_info_settings.xml @@ -64,6 +64,12 @@ android:title="@string/storage_scopes" settings:controller="com.android.settings.applications.appinfo.AppStorageScopesPreferenceController" /> + + + Date: Sun, 17 Apr 2022 18:00:53 +0300 Subject: [PATCH 69/97] add an ability to disable non-system apps from the "App info" screen --- .../AppButtonsPreferenceController.java | 41 ++++++++++++++++++- 1 file changed, 39 insertions(+), 2 deletions(-) diff --git a/src/com/android/settings/applications/appinfo/AppButtonsPreferenceController.java b/src/com/android/settings/applications/appinfo/AppButtonsPreferenceController.java index ff191ab4476..fa415d6e053 100644 --- a/src/com/android/settings/applications/appinfo/AppButtonsPreferenceController.java +++ b/src/com/android/settings/applications/appinfo/AppButtonsPreferenceController.java @@ -205,6 +205,15 @@ public void onDestroy() { } private class UninstallAndDisableButtonListener implements View.OnClickListener { + private boolean mChangeEnabledStateOfUserApp; + + UninstallAndDisableButtonListener() { + this(false); + } + + UninstallAndDisableButtonListener(boolean changeEnabledStateOfUserApp) { + mChangeEnabledStateOfUserApp = changeEnabledStateOfUserApp; + } @Override public void onClick(View v) { @@ -236,8 +245,13 @@ public void onClick(View v) { mUserId); if (admin != null && !uninstallBlockedBySystem) { RestrictedLockUtils.sendShowAdminSupportDetailsIntent(mActivity, admin); - } else if ((mAppEntry.info.flags & ApplicationInfo.FLAG_SYSTEM) != 0) { + } else if ((mAppEntry.info.flags & ApplicationInfo.FLAG_SYSTEM) != 0 || mChangeEnabledStateOfUserApp) { if (mAppEntry.info.enabled && !isDisabledUntilUsed()) { + if (mChangeEnabledStateOfUserApp) { + handleDialogClick(ButtonActionDialogFragment.DialogType.DISABLE); + return; + } + showDialogInner(ButtonActionDialogFragment.DialogType.DISABLE); } else { mMetricsFeatureProvider.action( @@ -468,6 +482,25 @@ void updateUninstallButton() { } mButtonsPref.setButton2Enabled(enabled); + + if (enabled && !isBundled) { + // "enabled" means "show uninstall button" in this context + int text; + int icon; + if (mAppEntry.info.enabled) { + text = R.string.disable_text; + icon = R.drawable.ic_settings_disable; + } else { + text = R.string.enable_text; + icon = R.drawable.ic_settings_enable; + } + mButtonsPref + .setButton4Text(text) + .setButton4Icon(icon) + .setButton4Visible(true) + .setButton4OnClickListener(new UninstallAndDisableButtonListener(true)) + ; + } } /** @@ -491,7 +524,9 @@ private void refreshAndFinishIfPossible(boolean removeTaskWhenFinishing) { @VisibleForTesting void updateForceStopButton() { - if (mDpm.packageHasActiveAdmins(mPackageInfo.packageName)) { + if (!mPackageInfo.applicationInfo.enabled) { + mButtonsPref.setButton3Visible(false); + } else if (mDpm.packageHasActiveAdmins(mPackageInfo.packageName)) { // User can't force stop device admin. Log.w(TAG, "User can't force stop device admin"); updateForceStopButtonInner(false /* enabled */); @@ -516,6 +551,7 @@ void updateForceStopButton() { @VisibleForTesting void updateForceStopButtonInner(boolean enabled) { + mButtonsPref.setButton3Visible(true); if (mAppsControlDisallowedBySystem) { mButtonsPref.setButton3Enabled(false); } else { @@ -530,6 +566,7 @@ void uninstallPkg(String packageName, boolean allUsers) { Uri packageUri = Uri.parse("package:" + packageName); Intent uninstallIntent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE, packageUri); uninstallIntent.putExtra(Intent.EXTRA_UNINSTALL_ALL_USERS, allUsers); + uninstallIntent.putExtra(Intent.EXTRA_UNINSTALL_SHOW_MORE_OPTIONS_BUTTON, false); mMetricsFeatureProvider.action(mActivity, SettingsEnums.ACTION_SETTINGS_UNINSTALL_APP); mFragment.startActivityForResult(uninstallIntent, mRequestUninstall); From 6cbab2d09df7928301c49d9e8874d95402164407 Mon Sep 17 00:00:00 2001 From: empratyush Date: Mon, 20 Jun 2022 22:16:29 +0300 Subject: [PATCH 70/97] 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 31895db32b1..51b4aa0d342 100644 --- a/Android.bp +++ b/Android.bp @@ -104,6 +104,7 @@ android_library { "Settings-change-ids", "androidx.room_room-runtime", "SystemUIUnfoldLib", + "ReverseWirelessCharging" ], plugins: ["androidx.room_room-compiler-plugin"], diff --git a/res/values/strings.xml b/res/values/strings.xml index a722a9aca54..a4dd51d9cf3 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -12350,4 +12350,7 @@ Installed: %1$s Updated: %1$s + + 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 121e1fe9628..e35c53a89e2 100644 --- a/res/xml/power_usage_summary.xml +++ b/res/xml/power_usage_summary.xml @@ -57,6 +57,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); + ((SwitchPreference) 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 d1d98ea787d4e5bee61435505e98ef70999ceb1f Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Fri, 15 Sep 2023 10:03:16 +0300 Subject: [PATCH 71/97] 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 17ffc8b1a7f..54b8ee7ce44 100755 --- a/res/values/config.xml +++ b/res/values/config.xml @@ -587,7 +587,7 @@ content://com.android.providers.media.documents/root/documents_root - true + false Allow running in background + "Warning: enabling this setting might cause some apps to stop working. + + Default value can be overridden per-app from the App info screen 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); + } +} diff --git a/src/com/android/settings/ext/DefaultOfPerAppSettingFragment.java b/src/com/android/settings/ext/DefaultOfPerAppSettingFragment.java new file mode 100644 index 00000000000..fca6febcedf --- /dev/null +++ b/src/com/android/settings/ext/DefaultOfPerAppSettingFragment.java @@ -0,0 +1,14 @@ +package com.android.settings.ext; + +import android.content.res.Resources; + +import androidx.annotation.StringRes; + +import com.android.settings.R; + +public abstract class DefaultOfPerAppSettingFragment extends BoolSettingFragment { + + protected CharSequence getMainSwitchSummary() { + return getText(R.string.summary_of_default_of_per_app_setting); + } +} From 8ea685b6474f3c87508dcb25e62ad1bfa2bfd934 Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Wed, 15 Nov 2023 13:44:08 +0200 Subject: [PATCH 74/97] add base class for App info single-choice fragments --- .../appinfo/RadioButtonAppInfoFragment.java | 156 ++++++++++++++++++ 1 file changed, 156 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..4e2da7917f1 --- /dev/null +++ b/src/com/android/settings/applications/appinfo/RadioButtonAppInfoFragment.java @@ -0,0 +1,156 @@ +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 androidx.annotation.Nullable; +import androidx.annotation.StringRes; +import androidx.appcompat.app.AlertDialog; +import androidx.preference.Preference; +import androidx.preference.PreferenceScreen; + +import com.android.settings.applications.AppInfoWithHeader; +import com.android.settingslib.widget.FooterPreference; +import com.android.settingslib.widget.SelectorWithWidgetPreference; + +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; + + @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); + } + + 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; + } + + @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 e3f0eb7f1ab7af46413d30b1636354e2d71305a1 Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Wed, 15 Nov 2023 13:44:23 +0200 Subject: [PATCH 75/97] add base classes for AppSwitch UIs --- res/values/strings_app_exploit_protection.xml | 25 +++ .../applications/appinfo/AswAdapter.kt | 38 +++++ .../appinfo/AswAppInfoFragment.java | 155 ++++++++++++++++++ .../appinfo/AswExploitProtectionFragment.java | 44 +++++ .../applications/appinfo/AswPrefController.kt | 11 ++ 5 files changed, 273 insertions(+) create mode 100644 res/values/strings_app_exploit_protection.xml create mode 100644 src/com/android/settings/applications/appinfo/AswAdapter.kt create mode 100644 src/com/android/settings/applications/appinfo/AswAppInfoFragment.java create mode 100644 src/com/android/settings/applications/appinfo/AswExploitProtectionFragment.java create mode 100644 src/com/android/settings/applications/appinfo/AswPrefController.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..6dacd66c2e2 --- /dev/null +++ b/res/values/strings_app_exploit_protection.xml @@ -0,0 +1,25 @@ + + + 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 Security 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 Security section. + + %1$s is enabled + + Exploit protection compatibility mode + diff --git a/src/com/android/settings/applications/appinfo/AswAdapter.kt b/src/com/android/settings/applications/appinfo/AswAdapter.kt new file mode 100644 index 00000000000..35b74b7091a --- /dev/null +++ b/src/com/android/settings/applications/appinfo/AswAdapter.kt @@ -0,0 +1,38 @@ +package com.android.settings.applications.appinfo + +import android.content.Context +import android.content.pm.ApplicationInfo +import android.content.pm.GosPackageState +import android.ext.settings.app.AppSwitch +import androidx.annotation.StringRes +import com.android.settings.R + +abstract class AswAdapter(val context: Context, val userId: Int = context.userId) { + abstract fun getAppSwitch(): T + + fun getPreferenceSummary(appInfo: ApplicationInfo): CharSequence { + val asw = getAppSwitch() + val si = AppSwitch.StateInfo() + val isOn = asw.get(context, userId, appInfo, GosPackageState.get(appInfo.packageName, userId), si) + return if (si.isUsingDefaultValue) { + getDefaultTitle(isOn) + } else { + if (isOn) getOnTitle() else getOffTitle() + } + } + + abstract fun getAswTitle(): CharSequence + + fun getDefaultTitle(isOn: Boolean): CharSequence { + return context.getString(R.string.aep_default, + if (isOn) getOnTitle() else getOffTitle()) + } + + open fun getOnTitle(): CharSequence = getText(R.string.aep_enabled) + + open fun getOffTitle(): CharSequence = getText(R.string.aep_disabled) + + protected fun getText(@StringRes id: Int): CharSequence = context.getText(id) + + protected fun getString(@StringRes id: Int): String = context.getString(id) +} diff --git a/src/com/android/settings/applications/appinfo/AswAppInfoFragment.java b/src/com/android/settings/applications/appinfo/AswAppInfoFragment.java new file mode 100644 index 00000000000..d8d101eb676 --- /dev/null +++ b/src/com/android/settings/applications/appinfo/AswAppInfoFragment.java @@ -0,0 +1,155 @@ +package com.android.settings.applications.appinfo; + +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; + +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 createAswAdapter(Context ctx); + + protected AswAdapter adapter; + + @Override + public void onCreate(Bundle savedInstanceState) { + adapter = createAswAdapter(requireContext()); + super.onCreate(savedInstanceState); + } + + @Override + protected CharSequence getTitle() { + return adapter.getAswTitle(); + } + + @Override + public Entry[] getEntries() { + Context ctx = adapter.getContext(); + AppSwitch asw = adapter.getAppSwitch(); + + int userId = mUserId; + var 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(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_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 -> { + var s = defaultValue ? adapter.getOnTitle() : adapter.getOffTitle(); + yield getString(R.string.aep_dvr_compat_config_hardening_opt_out, s.toString()); + } + default -> null; + }; + } + def.summary = summary; + } + + var enabled = createEntry(ID_ON, adapter.getOnTitle()); + enabled.isChecked = !isDefault && state; + enabled.isEnabled = enabled.isChecked || !isImmutable; + + var disabled = createEntry(ID_OFF, adapter.getOffTitle()); + 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; + } + } + + return new Entry[] { def, enabled, disabled }; + } + + @Nullable + protected CharSequence getSummaryForDefaultValueReason(int dvr) { + return null; + } + + @Nullable + protected CharSequence getSummaryForImmutabilityReason(int ir) { + return null; + } + + @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/appinfo/AswExploitProtectionFragment.java b/src/com/android/settings/applications/appinfo/AswExploitProtectionFragment.java new file mode 100644 index 00000000000..6369749592f --- /dev/null +++ b/src/com/android/settings/applications/appinfo/AswExploitProtectionFragment.java @@ -0,0 +1,44 @@ +package com.android.settings.applications.appinfo; + +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/applications/appinfo/AswPrefController.kt b/src/com/android/settings/applications/appinfo/AswPrefController.kt new file mode 100644 index 00000000000..5b0a37e82b4 --- /dev/null +++ b/src/com/android/settings/applications/appinfo/AswPrefController.kt @@ -0,0 +1,11 @@ +package com.android.settings.applications.appinfo + +import android.content.Context +import android.ext.settings.app.AppSwitch + +abstract class AswPrefController(ctx: Context, key: String, + val adapter: AswAdapter, +) : AppInfoPreferenceControllerBase(ctx, key) { + + override fun getSummary() = adapter.getPreferenceSummary(mAppEntry.info) +} From 9a1682efab67905a8fa9da0cff0d12f0719c32af Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Wed, 15 Nov 2023 13:44:56 +0200 Subject: [PATCH 76/97] add "Exploit protection" category to App info --- res/xml/app_info_settings.xml | 7 +++++++ ...ppExploitProtectionPrefCategoryController.java | 10 ++++++++++ .../appinfo/AppInfoDashboardFragment.java | 15 +++++++++++++++ 3 files changed, 32 insertions(+) create mode 100644 src/com/android/settings/applications/appinfo/AppExploitProtectionPrefCategoryController.java diff --git a/res/xml/app_info_settings.xml b/res/xml/app_info_settings.xml index 628f9722265..faf9bc0db1c 100644 --- a/res/xml/app_info_settings.xml +++ b/res/xml/app_info_settings.xml @@ -210,6 +210,13 @@ + + + + AppInfoPreferenceControllerBase prepare(Class cls) { + T res = use(cls); + res.setParentFragment(this); + return res; + } + @Override public void onCreate(Bundle icicle) { super.onCreate(icicle); From 3e77774b4df94976b45a456775f2c952ae10c944 Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Tue, 26 Sep 2023 10:34:50 +0300 Subject: [PATCH 77/97] add per-app setting for exploit protection compatibility mode --- res/values/strings_app_exploit_protection.xml | 1 + res/xml/app_info_settings.xml | 6 ++ ...oitProtectionCompatModePrefController.java | 63 +++++++++++++++++++ .../appinfo/AppInfoDashboardFragment.java | 1 + 4 files changed, 71 insertions(+) create mode 100644 src/com/android/settings/applications/appinfo/AppExploitProtectionCompatModePrefController.java diff --git a/res/values/strings_app_exploit_protection.xml b/res/values/strings_app_exploit_protection.xml index 6dacd66c2e2..88506c19306 100644 --- a/res/values/strings_app_exploit_protection.xml +++ b/res/values/strings_app_exploit_protection.xml @@ -22,4 +22,5 @@ This behavior can be disabled in the Security 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/res/xml/app_info_settings.xml b/res/xml/app_info_settings.xml index faf9bc0db1c..f98c377de78 100644 --- a/res/xml/app_info_settings.xml +++ b/res/xml/app_info_settings.xml @@ -215,6 +215,12 @@ android:title="@string/exploit_protection_category_title" settings:controller="com.android.settings.applications.appinfo.AppExploitProtectionPrefCategoryController"> + + diff --git a/src/com/android/settings/applications/appinfo/AppExploitProtectionCompatModePrefController.java b/src/com/android/settings/applications/appinfo/AppExploitProtectionCompatModePrefController.java new file mode 100644 index 00000000000..02b57d87a18 --- /dev/null +++ b/src/com/android/settings/applications/appinfo/AppExploitProtectionCompatModePrefController.java @@ -0,0 +1,63 @@ +package com.android.settings.applications.appinfo; + +import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.content.pm.GosPackageState; + +import androidx.preference.Preference; +import androidx.preference.SwitchPreference; + +public class AppExploitProtectionCompatModePrefController extends AppInfoPreferenceControllerBase + implements Preference.OnPreferenceChangeListener { + + public AppExploitProtectionCompatModePrefController(Context ctx, String key) { + super(ctx, key); + } + + @Override + public int getAvailabilityStatus() { + ApplicationInfo ai = mParent.getPackageInfo().applicationInfo; + return ai.isSystemApp() ? CONDITIONALLY_UNAVAILABLE : AVAILABLE; + } + + @Override + public void updateState(Preference preference) { + super.updateState(preference); + + GosPackageState ps = GosPackageState.get(getPackageName()); + + boolean checked = ps != null && ps.hasFlags(GosPackageState.FLAG_ENABLE_EXPLOIT_PROTECTION_COMPAT_MODE); + + ((SwitchPreference) preference).setChecked(checked); + } + + @Override + public boolean onPreferenceChange(Preference preference, Object newValue) { + boolean checked = (boolean) newValue; + + Runnable r = () -> { + GosPackageState.edit(getPackageName()) + .setFlagsState(GosPackageState.FLAG_ENABLE_EXPLOIT_PROTECTION_COMPAT_MODE, checked) + .killUidAfterApply() + .apply(); + + if (!mParent.refreshUi()) { + mParent.finish(); + } + }; + + if (checked) { + var d = AswExploitProtectionFragment.getExploitProtectionWarningOnDisable(mContext, r); + d.show(); + return false; + } + + r.run(); + + return true; + } + + private String getPackageName() { + return mParent.getPackageInfo().packageName; + } +} diff --git a/src/com/android/settings/applications/appinfo/AppInfoDashboardFragment.java b/src/com/android/settings/applications/appinfo/AppInfoDashboardFragment.java index 9701f981845..c91f5b4fe6c 100644 --- a/src/com/android/settings/applications/appinfo/AppInfoDashboardFragment.java +++ b/src/com/android/settings/applications/appinfo/AppInfoDashboardFragment.java @@ -233,6 +233,7 @@ public void onAttach(Context context) { aepCategory.setAppEntry(mAppEntry); AppInfoPreferenceControllerBase[] aepPrefControllers = { + prepare(AppExploitProtectionCompatModePrefController.class), }; aepCategory.setChildren(Arrays.asList(aepPrefControllers)); From e94491cf52bb443abd9db7b7444626828fd8500c Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Sat, 7 Oct 2023 21:28:08 +0300 Subject: [PATCH 78/97] add toggle for automatic exploit protection compatibility mode --- res/values/strings_ext.xml | 6 ++++++ res/xml/security_dashboard_settings.xml | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/res/values/strings_ext.xml b/res/values/strings_ext.xml index 39d7989db05..c378a64fdc1 100644 --- a/res/values/strings_ext.xml +++ b/res/values/strings_ext.xml @@ -110,6 +110,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. Default value can be overridden per-app from the App info screen diff --git a/res/xml/security_dashboard_settings.xml b/res/xml/security_dashboard_settings.xml index 07dc3aa714b..fb04ea2ce70 100644 --- a/res/xml/security_dashboard_settings.xml +++ b/res/xml/security_dashboard_settings.xml @@ -65,6 +65,12 @@ android:fragment="com.android.settings.security.ExecSpawningFragment" settings:controller="com.android.settings.security.ExecSpawningPrefController" /> + + Date: Thu, 16 Nov 2023 17:23:47 +0200 Subject: [PATCH 79/97] add per-app setting for hardened_malloc --- res/values/strings_app_exploit_protection.xml | 8 ++++ res/xml/app_info_settings.xml | 5 +++ .../applications/appinfo/AppHardenedMalloc.kt | 41 +++++++++++++++++++ .../appinfo/AppInfoDashboardFragment.java | 1 + 4 files changed, 55 insertions(+) create mode 100644 src/com/android/settings/applications/appinfo/AppHardenedMalloc.kt diff --git a/res/values/strings_app_exploit_protection.xml b/res/values/strings_app_exploit_protection.xml index 88506c19306..451dbd345e7 100644 --- a/res/values/strings_app_exploit_protection.xml +++ b/res/values/strings_app_exploit_protection.xml @@ -23,4 +23,12 @@ This behavior can be disabled in the Security 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/app_info_settings.xml b/res/xml/app_info_settings.xml index f98c377de78..1d5b8d4e134 100644 --- a/res/xml/app_info_settings.xml +++ b/res/xml/app_info_settings.xml @@ -221,6 +221,11 @@ android:summary="@string/aep_compat_mode_summary" settings:controller="com.android.settings.applications.appinfo.AppExploitProtectionCompatModePrefController" /> + + diff --git a/src/com/android/settings/applications/appinfo/AppHardenedMalloc.kt b/src/com/android/settings/applications/appinfo/AppHardenedMalloc.kt new file mode 100644 index 00000000000..c7b169aaacd --- /dev/null +++ b/src/com/android/settings/applications/appinfo/AppHardenedMalloc.kt @@ -0,0 +1,41 @@ +package com.android.settings.applications.appinfo + +import android.content.Context +import android.ext.settings.app.AppSwitch +import android.ext.settings.app.AswUseHardenedMalloc +import com.android.settings.R +import com.android.settingslib.widget.FooterPreference + +class AswAdapterUseHardenedMalloc(ctx: Context) : AswAdapter(ctx) { + + override fun getAppSwitch() = AswUseHardenedMalloc.I + + override fun getAswTitle() = getText(R.string.aep_hmalloc) +} + +class AppHardenedMallocPrefController(ctx: Context, key: String) : + AswPrefController(ctx, key, AswAdapterUseHardenedMalloc(ctx)) { + + override fun getDetailFragmentClass() = AppHardenedMallocFragment::class.java +} + +class AppHardenedMallocFragment : AswExploitProtectionFragment() { + + override fun createAswAdapter(ctx: Context) = AswAdapterUseHardenedMalloc(ctx) + + 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") + } +} diff --git a/src/com/android/settings/applications/appinfo/AppInfoDashboardFragment.java b/src/com/android/settings/applications/appinfo/AppInfoDashboardFragment.java index c91f5b4fe6c..667d5a962b7 100644 --- a/src/com/android/settings/applications/appinfo/AppInfoDashboardFragment.java +++ b/src/com/android/settings/applications/appinfo/AppInfoDashboardFragment.java @@ -234,6 +234,7 @@ public void onAttach(Context context) { AppInfoPreferenceControllerBase[] aepPrefControllers = { prepare(AppExploitProtectionCompatModePrefController.class), + prepare(AppHardenedMallocPrefController.class), }; aepCategory.setChildren(Arrays.asList(aepPrefControllers)); From 26e59ce78ff6b64d4c1dbec17d24da395a4caee0 Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Thu, 16 Nov 2023 17:23:35 +0200 Subject: [PATCH 80/97] add dev mode per-app setting for extended virtual address space --- res/values/strings_app_exploit_protection.xml | 5 +++ res/xml/app_info_settings.xml | 5 +++ .../appinfo/AppExtendedVaSpace.kt | 41 +++++++++++++++++++ .../appinfo/AppInfoDashboardFragment.java | 1 + 4 files changed, 52 insertions(+) create mode 100644 src/com/android/settings/applications/appinfo/AppExtendedVaSpace.kt diff --git a/res/values/strings_app_exploit_protection.xml b/res/values/strings_app_exploit_protection.xml index 451dbd345e7..66a3528125f 100644 --- a/res/values/strings_app_exploit_protection.xml +++ b/res/values/strings_app_exploit_protection.xml @@ -31,4 +31,9 @@ This behavior can be disabled in the Security 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/app_info_settings.xml b/res/xml/app_info_settings.xml index 1d5b8d4e134..d942feac434 100644 --- a/res/xml/app_info_settings.xml +++ b/res/xml/app_info_settings.xml @@ -226,6 +226,11 @@ android:title="@string/aep_hmalloc" settings:controller="com.android.settings.applications.appinfo.AppHardenedMallocPrefController" /> + + diff --git a/src/com/android/settings/applications/appinfo/AppExtendedVaSpace.kt b/src/com/android/settings/applications/appinfo/AppExtendedVaSpace.kt new file mode 100644 index 00000000000..b1257617f43 --- /dev/null +++ b/src/com/android/settings/applications/appinfo/AppExtendedVaSpace.kt @@ -0,0 +1,41 @@ +package com.android.settings.applications.appinfo + +import android.content.Context +import android.ext.settings.app.AppSwitch +import android.ext.settings.app.AswUseExtendedVaSpace +import com.android.settings.R +import com.android.settings.ext.ExtSettingControllerHelper +import com.android.settingslib.widget.FooterPreference + +class AswAdapterUseExtendedVaSpace(ctx: Context) : AswAdapter(ctx) { + + override fun getAppSwitch() = AswUseExtendedVaSpace.I + + override fun getAswTitle() = getText(R.string.aep_ext_va_space) +} + +class AppExtendedVaSpacePrefController(ctx: Context, key: String) : + AswPrefController(ctx, key, AswAdapterUseExtendedVaSpace(ctx)) { + + override fun getDetailFragmentClass() = AppExtendedVaSpaceFragment::class.java + + override fun getAvailabilityStatus() = ExtSettingControllerHelper.getDevModeSettingAvailability(mContext) +} + +class AppExtendedVaSpaceFragment : AswExploitProtectionFragment() { + + override fun createAswAdapter(ctx: Context) = AswAdapterUseExtendedVaSpace(ctx) + + 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) + } +} diff --git a/src/com/android/settings/applications/appinfo/AppInfoDashboardFragment.java b/src/com/android/settings/applications/appinfo/AppInfoDashboardFragment.java index 667d5a962b7..fb5a86f535e 100644 --- a/src/com/android/settings/applications/appinfo/AppInfoDashboardFragment.java +++ b/src/com/android/settings/applications/appinfo/AppInfoDashboardFragment.java @@ -235,6 +235,7 @@ public void onAttach(Context context) { AppInfoPreferenceControllerBase[] aepPrefControllers = { prepare(AppExploitProtectionCompatModePrefController.class), prepare(AppHardenedMallocPrefController.class), + prepare(AppExtendedVaSpacePrefController.class), }; aepCategory.setChildren(Arrays.asList(aepPrefControllers)); From 5ee19abb90141be40ec544824ee88c4cc9fef976 Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Wed, 15 Nov 2023 13:51:07 +0200 Subject: [PATCH 81/97] add per-app setting for native debugging --- AndroidManifest.xml | 18 +++++++ res/values/strings_app_exploit_protection.xml | 2 + res/xml/app_info_settings.xml | 5 ++ src/com/android/settings/Settings.java | 2 + .../appinfo/AppInfoDashboardFragment.java | 1 + .../appinfo/AppNativeDebugging.kt | 48 +++++++++++++++++++ .../core/gateway/SettingsGateway.java | 1 + 7 files changed, 77 insertions(+) create mode 100644 src/com/android/settings/applications/appinfo/AppNativeDebugging.kt diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 64f42a71bdc..8b67772accf 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -4969,5 +4969,23 @@ tools:node="remove" /> + + + + + + + + + + + + + diff --git a/res/values/strings_app_exploit_protection.xml b/res/values/strings_app_exploit_protection.xml index 66a3528125f..8cdece1e891 100644 --- a/res/values/strings_app_exploit_protection.xml +++ b/res/values/strings_app_exploit_protection.xml @@ -36,4 +36,6 @@ This behavior can be disabled in the Security section. 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 debugging is always blocked for preinstalled apps diff --git a/res/xml/app_info_settings.xml b/res/xml/app_info_settings.xml index d942feac434..f5855f80d1d 100644 --- a/res/xml/app_info_settings.xml +++ b/res/xml/app_info_settings.xml @@ -231,6 +231,11 @@ android:title="@string/aep_ext_va_space" settings:controller="com.android.settings.applications.appinfo.AppExtendedVaSpacePrefController" /> + + diff --git a/src/com/android/settings/Settings.java b/src/com/android/settings/Settings.java index 60a5b808c82..d67e0e08179 100644 --- a/src/com/android/settings/Settings.java +++ b/src/com/android/settings/Settings.java @@ -516,4 +516,6 @@ public static class AdaptiveBrightnessActivity extends SettingsActivity { /* emp * Activity for OneHandedSettings */ public static class OneHandedSettingsActivity extends SettingsActivity { /* empty */ } + + public static class AppNativeDebuggingActivity extends SettingsActivity {} } diff --git a/src/com/android/settings/applications/appinfo/AppInfoDashboardFragment.java b/src/com/android/settings/applications/appinfo/AppInfoDashboardFragment.java index fb5a86f535e..c158439d79a 100644 --- a/src/com/android/settings/applications/appinfo/AppInfoDashboardFragment.java +++ b/src/com/android/settings/applications/appinfo/AppInfoDashboardFragment.java @@ -236,6 +236,7 @@ public void onAttach(Context context) { prepare(AppExploitProtectionCompatModePrefController.class), prepare(AppHardenedMallocPrefController.class), prepare(AppExtendedVaSpacePrefController.class), + prepare(AppNativeDebuggingPrefController.class), }; aepCategory.setChildren(Arrays.asList(aepPrefControllers)); diff --git a/src/com/android/settings/applications/appinfo/AppNativeDebugging.kt b/src/com/android/settings/applications/appinfo/AppNativeDebugging.kt new file mode 100644 index 00000000000..c99420935b2 --- /dev/null +++ b/src/com/android/settings/applications/appinfo/AppNativeDebugging.kt @@ -0,0 +1,48 @@ +package com.android.settings.applications.appinfo + +import android.content.Context +import android.ext.settings.app.AswDenyNativeDebug +import android.ext.settings.app.AppSwitch +import com.android.settings.R +import com.android.settingslib.widget.FooterPreference + +class AswAdapterNativeDebugging(ctx: Context) : AswAdapter(ctx) { + + override fun getAppSwitch() = AswDenyNativeDebug.I + + override fun getAswTitle() = getText(R.string.native_debugging_title) + + override fun getOnTitle() = getText(R.string.aep_blocked) + override fun getOffTitle() = getText(R.string.aep_allowed) +} + +class AppNativeDebuggingPrefController(ctx: Context, key: String) : + AswPrefController(ctx, key, AswAdapterNativeDebugging(ctx)) { + + override fun getDetailFragmentClass() = AppNativeDebuggingFragment::class.java +} + +class AppNativeDebuggingFragment : AswExploitProtectionFragment() { + + override fun createAswAdapter(ctx: Context) = AswAdapterNativeDebugging(ctx) + + override fun getSummaryForImmutabilityReason(ir: Int): CharSequence? { + val id = when (ir) { + AppSwitch.IR_IS_SYSTEM_APP -> R.string.native_debug_dvr_is_system_app + else -> return null + } + return getText(id) + } + + override fun getSummaryForDefaultValueReason(dvr: Int): CharSequence? { + val id = when (dvr) { + AppSwitch.DVR_DEFAULT_SETTING -> R.string.aep_dvr_default_security_setting + else -> return null + } + return getText(id) + } + + override fun updateFooter(fp: FooterPreference) { + fp.setTitle(R.string.native_debugging_footer) + } +} diff --git a/src/com/android/settings/core/gateway/SettingsGateway.java b/src/com/android/settings/core/gateway/SettingsGateway.java index 7b1abaf8b24..152457c7d19 100644 --- a/src/com/android/settings/core/gateway/SettingsGateway.java +++ b/src/com/android/settings/core/gateway/SettingsGateway.java @@ -202,6 +202,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.appinfo.AppNativeDebuggingFragment.class.getName(), AdvancedConnectedDeviceDashboardFragment.class.getName(), CreateShortcut.class.getName(), BluetoothPairingDetail.class.getName(), From 0f8218217ff7dbc171a3b6f92b6a4c66b00bc4b8 Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Wed, 24 May 2023 19:00:36 +0300 Subject: [PATCH 82/97] add setting for default value of per-app native debugging setting --- res/values/strings_ext.xml | 8 +++++ res/xml/security_dashboard_settings.xml | 6 ++++ .../security/NativeDebuggingFragment.java | 34 +++++++++++++++++++ .../NativeDebuggingPrefController.java | 20 +++++++++++ 4 files changed, 68 insertions(+) create mode 100644 src/com/android/settings/security/NativeDebuggingFragment.java create mode 100644 src/com/android/settings/security/NativeDebuggingPrefController.java diff --git a/res/values/strings_ext.xml b/res/values/strings_ext.xml index c378a64fdc1..b67820f572e 100644 --- a/res/values/strings_ext.xml +++ b/res/values/strings_ext.xml @@ -97,6 +97,14 @@ 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. + Native code debugging + Block for third-party apps by default + Blocked by default + Allowed for third-party apps by default + +Native code debugging (ptrace) slightly weakens the app sandbox. Some apps (most notably banking apps) use it as a tampering detection tool. + + App installs and updates diff --git a/res/xml/security_dashboard_settings.xml b/res/xml/security_dashboard_settings.xml index fb04ea2ce70..301769721bb 100644 --- a/res/xml/security_dashboard_settings.xml +++ b/res/xml/security_dashboard_settings.xml @@ -71,6 +71,12 @@ android:summary="@string/allow_automatic_per_app_epcm_summary" settings:boolSettingField="android.ext.settings.ExtSettings ALLOW_DISABLING_HARDENING_VIA_APP_COMPAT_CONFIG" /> + + Date: Wed, 15 Nov 2023 13:51:18 +0200 Subject: [PATCH 83/97] add per-app setting for memory tagging --- AndroidManifest.xml | 17 +++++++ res/values/strings_app_exploit_protection.xml | 10 ++++ res/xml/app_info_settings.xml | 5 ++ src/com/android/settings/Settings.java | 2 + .../appinfo/AppInfoDashboardFragment.java | 1 + .../applications/appinfo/AppMemoryTagging.kt | 51 +++++++++++++++++++ .../core/gateway/SettingsGateway.java | 1 + 7 files changed, 87 insertions(+) create mode 100644 src/com/android/settings/applications/appinfo/AppMemoryTagging.kt diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 8b67772accf..5b8451ceed5 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -4987,5 +4987,22 @@ android:value="@string/menu_key_apps"/> + + + + + + + + + + + + diff --git a/res/values/strings_app_exploit_protection.xml b/res/values/strings_app_exploit_protection.xml index 8cdece1e891..085bb68eb41 100644 --- a/res/values/strings_app_exploit_protection.xml +++ b/res/values/strings_app_exploit_protection.xml @@ -38,4 +38,14 @@ This behavior can be disabled in the Security section. Required by hardened_malloc Native debugging is always blocked for preinstalled apps + + 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 + + Memory tagging is always enabled for apps that don’t have native code + + This app has opted-in to memory tagging diff --git a/res/xml/app_info_settings.xml b/res/xml/app_info_settings.xml index f5855f80d1d..32d7dccc505 100644 --- a/res/xml/app_info_settings.xml +++ b/res/xml/app_info_settings.xml @@ -226,6 +226,11 @@ android:title="@string/aep_hmalloc" settings:controller="com.android.settings.applications.appinfo.AppHardenedMallocPrefController" /> + + (ctx) { + + override fun getAppSwitch() = AswUseMemoryTagging.I + + override fun getAswTitle() = getText(R.string.aep_memtag) +} + +class AppMemtagPrefController(ctx: Context, key: String) : + AswPrefController(ctx, key, AswAdapterUseMemoryTagging(ctx)) { + + override fun getDetailFragmentClass() = AppMemtagFragment::class.java + + private val isSupported = Zygote.nativeSupportsMemoryTagging() + override fun getAvailabilityStatus() = if (isSupported) AVAILABLE else UNSUPPORTED_ON_DEVICE +} + +class AppMemtagFragment : AswExploitProtectionFragment() { + + override fun createAswAdapter(ctx: Context) = AswAdapterUseMemoryTagging(ctx) + + 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 getSummaryForDefaultValueReason(dvr: Int): CharSequence? { + val id = when (dvr) { + AppSwitch.DVR_DEFAULT_SETTING -> R.string.aep_dvr_default_security_setting + else -> return null + } + return getText(id) + } + + override fun updateFooter(fp: FooterPreference) { + fp.setTitle(R.string.aep_memtag_footer) + } +} diff --git a/src/com/android/settings/core/gateway/SettingsGateway.java b/src/com/android/settings/core/gateway/SettingsGateway.java index 152457c7d19..9d564305c58 100644 --- a/src/com/android/settings/core/gateway/SettingsGateway.java +++ b/src/com/android/settings/core/gateway/SettingsGateway.java @@ -203,6 +203,7 @@ public class SettingsGateway { */ public static final String[] ENTRY_FRAGMENTS = { com.android.settings.applications.appinfo.AppNativeDebuggingFragment.class.getName(), + com.android.settings.applications.appinfo.AppMemtagFragment.class.getName(), AdvancedConnectedDeviceDashboardFragment.class.getName(), CreateShortcut.class.getName(), BluetoothPairingDetail.class.getName(), From ba91a99c6fc02cab963dee25e049fb85aea376fe Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Wed, 15 Nov 2023 13:45:25 +0200 Subject: [PATCH 84/97] add setting for default value of per-app memory tagging setting --- res/values/strings_app_exploit_protection.xml | 14 ++++++ res/xml/security_dashboard_settings.xml | 6 +++ .../settings/security/ForceAppMemtag.kt | 45 +++++++++++++++++++ 3 files changed, 65 insertions(+) create mode 100644 src/com/android/settings/security/ForceAppMemtag.kt diff --git a/res/values/strings_app_exploit_protection.xml b/res/values/strings_app_exploit_protection.xml index 085bb68eb41..a8b765d3f5f 100644 --- a/res/values/strings_app_exploit_protection.xml +++ b/res/values/strings_app_exploit_protection.xml @@ -48,4 +48,18 @@ This behavior can be disabled in the Security section. Memory tagging is always enabled for apps that don’t have native code This app has opted-in to memory tagging + + Memory tagging in third-party apps + 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/security_dashboard_settings.xml b/res/xml/security_dashboard_settings.xml index 301769721bb..b2babcf4560 100644 --- a/res/xml/security_dashboard_settings.xml +++ b/res/xml/security_dashboard_settings.xml @@ -71,6 +71,12 @@ android:summary="@string/allow_automatic_per_app_epcm_summary" settings:boolSettingField="android.ext.settings.ExtSettings ALLOW_DISABLING_HARDENING_VIA_APP_COMPAT_CONFIG" /> + + Date: Mon, 27 Nov 2023 21:47:26 +0200 Subject: [PATCH 85/97] add toggle for system process crash notifications --- res/values/strings_ext.xml | 4 ++++ res/xml/security_dashboard_settings.xml | 7 +++++++ 2 files changed, 11 insertions(+) diff --git a/res/values/strings_ext.xml b/res/values/strings_ext.xml index b67820f572e..6a18389072e 100644 --- a/res/values/strings_ext.xml +++ b/res/values/strings_ext.xml @@ -127,4 +127,8 @@ Native code debugging (ptrace) slightly weakens the app sandbox. Some apps (most "Warning: enabling this setting might cause some apps to stop working. Default value can be overridden per-app from the App info screen + + Notify about system process crashes + Such crashes may indicate exploitation attempts + diff --git a/res/xml/security_dashboard_settings.xml b/res/xml/security_dashboard_settings.xml index b2babcf4560..ec724f0536f 100644 --- a/res/xml/security_dashboard_settings.xml +++ b/res/xml/security_dashboard_settings.xml @@ -99,6 +99,13 @@ android:title="@string/security_settings_biometric_preference_title" android:summary="@string/summary_placeholder" settings:keywords="@string/keywords_biometric_settings" /> + + Date: Fri, 29 Sep 2023 16:16:00 +0300 Subject: [PATCH 86/97] 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 | 44 +++++++++++++++++++ 3 files changed, 55 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 6a18389072e..9f4813ba8f1 100644 --- a/res/values/strings_ext.xml +++ b/res/values/strings_ext.xml @@ -105,6 +105,11 @@ There are HTTP, HTTPS, DNS, DNS-over-TLS and DNS-over-HTTPS connectivity checks. Native code debugging (ptrace) slightly weakens the app sandbox. Some apps (most notably banking apps) use it as a tampering detection tool. + Widevine provisioning + Enabled (GrapheneOS proxy) + Enabled (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 825e0f98b80..bb826490104 100644 --- a/res/xml/network_provider_internet.xml +++ b/res/xml/network_provider_internet.xml @@ -150,4 +150,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..7ebc5d12bee --- /dev/null +++ b/src/com/android/settings/network/WidevineProvisioningPrefController.java @@ -0,0 +1,44 @@ +/* + * 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.ExtSettings; +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, ExtSettings.WIDEVINE_PROVISIONING_SERVER); + } + + @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); + } +} \ No newline at end of file From 94cc1f66c112cbc9d77652c7e70cf7589e89d171 Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Wed, 27 Dec 2023 21:48:57 +0200 Subject: [PATCH 87/97] add config for setupdesign and setupcompat libraries These libraries are used by several AOSP components and proprietary Google apps for creating consistent SetupWizard-like UIs. For more info, see methods that call "com.google.android.setupwizard.partner" ContentProvider in external/setupcompat and external/setupdesign. --- AndroidManifest.xml | 6 ++ .../settings/SetupDesignConfigProvider.java | 75 +++++++++++++++++++ 2 files changed, 81 insertions(+) create mode 100644 src/com/android/settings/SetupDesignConfigProvider.java diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 5b8451ceed5..882f690b080 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -4962,6 +4962,12 @@ android:value="UsageStats"/> + + + res.putString(method, "glif_v4_light"); + + case + "applyGlifThemeControlledTransition", + "isDynamicColorEnabled", + "isEmbeddedActivityOnePaneEnabled", + "isFullDynamicColorEnabled", + "IsMaterialYouStyleEnabled", + "isNeutralButtonStyleEnabled", + "isSuwDayNightEnabled" -> + res.putBoolean(method, true); + + case "getDeviceName" -> { + String name = Settings.Global.getString(getContext().getContentResolver(), Settings.Global.DEVICE_NAME); + if (TextUtils.isEmpty(name)) { + name = Build.MODEL; + } + res.putCharSequence(method, name); + } + } + return res; + } + + @Override + public Cursor query(Uri uri, String[] strings, String s, String[] strings1, String s1) { + throw new UnsupportedOperationException(); + } + + @Override + public String getType(Uri uri) { + throw new UnsupportedOperationException(); + } + + @Override + public Uri insert(Uri uri, ContentValues contentValues) { + throw new UnsupportedOperationException(); + } + + @Override + public int delete(Uri uri, String s, String[] strings) { + throw new UnsupportedOperationException(); + } + + @Override + public int update(Uri uri, ContentValues contentValues, String s, String[] strings) { + throw new UnsupportedOperationException(); + } +} From c39e7ea0dd825a79073eaff7374cf0804a6aa448 Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Sat, 23 Dec 2023 11:15:54 +0200 Subject: [PATCH 88/97] fixup! add link to Sandboxed Google Play settings GmsCompat.isGmsApp() was renamed to GmsCompat.isEnabledFor(). --- .../applications/GmsCompatAppController.java | 23 +++---------------- 1 file changed, 3 insertions(+), 20 deletions(-) diff --git a/src/com/android/settings/applications/GmsCompatAppController.java b/src/com/android/settings/applications/GmsCompatAppController.java index ff8232d3601..32fe7d05e60 100644 --- a/src/com/android/settings/applications/GmsCompatAppController.java +++ b/src/com/android/settings/applications/GmsCompatAppController.java @@ -1,23 +1,8 @@ -/* - * 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.applications; import android.app.compat.gms.GmsCompat; import android.content.Context; import android.content.Intent; -import android.content.IntentFilter; import android.os.UserHandle; import android.text.TextUtils; @@ -28,11 +13,9 @@ import com.android.settings.core.BasePreferenceController; public class GmsCompatAppController extends BasePreferenceController { - private final Context context; public GmsCompatAppController(Context context, String key) { super(context, key); - this.context = context; } @Override @@ -42,7 +25,7 @@ public int getAvailabilityStatus() { workProfile.getIdentifier() : UserHandle.myUserId(); - return GmsCompat.isGmsApp(GmsInfo.PACKAGE_GMS_CORE, userId) ? + return GmsCompat.isEnabledFor(GmsInfo.PACKAGE_GMS_CORE, userId) ? AVAILABLE : DISABLED_FOR_USER; } @@ -56,9 +39,9 @@ public boolean handlePreferenceTreeClick(Preference preference) { UserHandle workProfile = getWorkProfileUser(); if (workProfile != null) { - context.startActivityAsUser(intent, workProfile); + mContext.startActivityAsUser(intent, workProfile); } else { - context.startActivity(intent); + mContext.startActivity(intent); } return true; } From 5d3d0ccd1efed7f67ebd7cb26c5329f64aeb7844 Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Mon, 18 Dec 2023 15:38:16 +0200 Subject: [PATCH 89/97] 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 140e2d17b10338a2e4e3c6259fdd79c6e9c93168 Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Sat, 6 Jan 2024 19:37:47 +0200 Subject: [PATCH 90/97] add link to logcat viewer to System category --- 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 882f690b080..72a48c055ca 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -133,6 +133,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 1f5559f0927..87b71254552 100644 --- a/res/xml/system_dashboard_fragment.xml +++ b/res/xml/system_dashboard_fragment.xml @@ -92,6 +92,13 @@ + + Date: Sat, 6 Jan 2024 19:38:42 +0200 Subject: [PATCH 91/97] add link to logcat viewer to App info screen --- res/xml/app_info_settings.xml | 5 +++++ .../appinfo/AppInfoDashboardFragment.java | 1 + .../appinfo/AppLogcatPrefController.java | 20 +++++++++++++++++++ 3 files changed, 26 insertions(+) create mode 100644 src/com/android/settings/applications/appinfo/AppLogcatPrefController.java diff --git a/res/xml/app_info_settings.xml b/res/xml/app_info_settings.xml index 32d7dccc505..3ece9ea927e 100644 --- a/res/xml/app_info_settings.xml +++ b/res/xml/app_info_settings.xml @@ -144,6 +144,11 @@ android:title="@string/sms_application_title" android:summary="@string/summary_placeholder" /> + + Date: Thu, 11 Jan 2024 18:02:33 +0200 Subject: [PATCH 92/97] add deep link to app hardened_malloc settings It's used by the "hardened_malloc detected an error in $APP" notification. --- AndroidManifest.xml | 17 +++++++++++++++++ src/com/android/settings/Settings.java | 2 ++ .../settings/core/gateway/SettingsGateway.java | 1 + 3 files changed, 20 insertions(+) diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 72a48c055ca..ecc17058f57 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -5011,5 +5011,22 @@ android:value="@string/menu_key_apps"/> + + + + + + + + + + + + diff --git a/src/com/android/settings/Settings.java b/src/com/android/settings/Settings.java index a7207cb372b..5ac7b9181c7 100644 --- a/src/com/android/settings/Settings.java +++ b/src/com/android/settings/Settings.java @@ -520,4 +520,6 @@ public static class OneHandedSettingsActivity extends SettingsActivity { /* empt public static class AppNativeDebuggingActivity extends SettingsActivity {} public static class AppMemtagActivity extends SettingsActivity {} + + public static class AppHardenedMallocActivity extends SettingsActivity {} } diff --git a/src/com/android/settings/core/gateway/SettingsGateway.java b/src/com/android/settings/core/gateway/SettingsGateway.java index 9d564305c58..6c07d3c6d01 100644 --- a/src/com/android/settings/core/gateway/SettingsGateway.java +++ b/src/com/android/settings/core/gateway/SettingsGateway.java @@ -204,6 +204,7 @@ public class SettingsGateway { public static final String[] ENTRY_FRAGMENTS = { com.android.settings.applications.appinfo.AppNativeDebuggingFragment.class.getName(), com.android.settings.applications.appinfo.AppMemtagFragment.class.getName(), + com.android.settings.applications.appinfo.AppHardenedMallocFragment.class.getName(), AdvancedConnectedDeviceDashboardFragment.class.getName(), CreateShortcut.class.getName(), BluetoothPairingDetail.class.getName(), From 1798d13e956b8bfcd6b6b480817d75b6fe271426 Mon Sep 17 00:00:00 2001 From: Griffin Millender Date: Sat, 13 Jan 2024 20:25:59 -0600 Subject: [PATCH 93/97] Add allow input device toggle to bluetooth pairing dialog --- res/layout/bluetooth_pin_confirm.xml | 9 ++++ res/values/strings_ext.xml | 2 + .../bluetooth/BluetoothPairingController.java | 50 +++++++++++++++++++ .../bluetooth/BluetoothPairingDialog.java | 1 + .../BluetoothPairingDialogFragment.java | 7 +++ 5 files changed, 69 insertions(+) diff --git a/res/layout/bluetooth_pin_confirm.xml b/res/layout/bluetooth_pin_confirm.xml index 7b5b04670e8..241d744c35d 100644 --- a/res/layout/bluetooth_pin_confirm.xml +++ b/res/layout/bluetooth_pin_confirm.xml @@ -85,6 +85,15 @@ android:layout_marginEnd="@dimen/bluetooth_dialog_padding" android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Body1" /> + + diff --git a/res/values/strings_ext.xml b/res/values/strings_ext.xml index e5d37d5038f..188b4b64e52 100644 --- a/res/values/strings_ext.xml +++ b/res/values/strings_ext.xml @@ -138,4 +138,6 @@ Native code debugging (ptrace) slightly weakens the app sandbox. Some apps (most View logs + Allow input device + diff --git a/src/com/android/settings/bluetooth/BluetoothPairingController.java b/src/com/android/settings/bluetooth/BluetoothPairingController.java index f75d301ad22..09802840e66 100644 --- a/src/com/android/settings/bluetooth/BluetoothPairingController.java +++ b/src/com/android/settings/bluetooth/BluetoothPairingController.java @@ -15,8 +15,13 @@ */ package com.android.settings.bluetooth; +import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_ALLOWED; +import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; + +import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothClass; import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothHidHost; import android.bluetooth.BluetoothProfile; import android.content.Context; import android.content.Intent; @@ -73,6 +78,22 @@ public class BluetoothPairingController implements OnCheckedChangeListener, private boolean mIsLeAudio; private boolean mIsLeContactSharingEnabled; private boolean mIsLateBonding; + private boolean mIsHid = false; + private boolean mIsHidEnabled = false; + private BluetoothHidHost mBluetoothHidHost; + + // These callbacks run on the main thread. + private final class HidHostServiceListener + implements BluetoothProfile.ServiceListener { + + public void onServiceConnected(int profile, BluetoothProfile proxy) { + mBluetoothHidHost = (BluetoothHidHost) proxy; + } + + public void onServiceDisconnected(int profile) { + mBluetoothHidHost = null; + } + } /** * Creates an instance of a BluetoothPairingController. @@ -85,6 +106,9 @@ public BluetoothPairingController(Intent intent, Context context) { mBluetoothManager = Utils.getLocalBtManager(context); mDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); + BluetoothAdapter.getDefaultAdapter().getProfileProxy(context, new HidHostServiceListener(), + BluetoothProfile.HID_HOST); + String message = ""; if (mBluetoothManager == null) { throw new IllegalStateException("Could not obtain LocalBluetoothManager"); @@ -123,10 +147,21 @@ public BluetoothPairingController(Intent intent, Context context) { + mIsLeContactSharingEnabled + " isCooridnatedSetMember " + mIsCoordinatedSetMember); } + + BluetoothClass bluetoothClass = mDevice.getBluetoothClass(); + if (bluetoothClass != null) { + mIsHid = bluetoothClass.doesClassMatch(BluetoothClass.PROFILE_HID); + } } @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { + if (buttonView != null) { + if (buttonView.getId() == R.id.hid_enabled_confirm) { + mIsHidEnabled = isChecked; + return; + } + } if (isChecked) { mPbapAllowed = true; } else { @@ -226,6 +261,21 @@ boolean isLeContactSharingEnabled() { return mIsLeContactSharingEnabled; } + public boolean isHidDevice() { + return mIsHid; + } + + public boolean getHidEnabledState() { + return mIsHidEnabled; + } + + public void onDialogDismissed(boolean success) { + if (success) { + mBluetoothHidHost.setConnectionPolicy(mDevice, + mIsHidEnabled ? CONNECTION_POLICY_ALLOWED : CONNECTION_POLICY_FORBIDDEN); + } + } + /** * A method whether the device allows to show the le audio's contact sharing. * diff --git a/src/com/android/settings/bluetooth/BluetoothPairingDialog.java b/src/com/android/settings/bluetooth/BluetoothPairingDialog.java index 0cd36d0f471..8279e0eb975 100644 --- a/src/com/android/settings/bluetooth/BluetoothPairingDialog.java +++ b/src/com/android/settings/bluetooth/BluetoothPairingDialog.java @@ -52,6 +52,7 @@ public void onReceive(Context context, Intent intent) { BluetoothDevice.ERROR); if (bondState == BluetoothDevice.BOND_BONDED || bondState == BluetoothDevice.BOND_NONE) { + mBluetoothPairingController.onDialogDismissed(bondState == BluetoothDevice.BOND_BONDED); dismiss(); } } else if (BluetoothDevice.ACTION_PAIRING_CANCEL.equals(action)) { diff --git a/src/com/android/settings/bluetooth/BluetoothPairingDialogFragment.java b/src/com/android/settings/bluetooth/BluetoothPairingDialogFragment.java index e11c275bded..37f4a75b82c 100644 --- a/src/com/android/settings/bluetooth/BluetoothPairingDialogFragment.java +++ b/src/com/android/settings/bluetooth/BluetoothPairingDialogFragment.java @@ -341,6 +341,7 @@ private View createView() { TextView messagePairing = (TextView) view.findViewById(R.id.pairing_code_message); CheckBox contactSharing = (CheckBox) view.findViewById( R.id.phonebook_sharing_message_confirm_pin); + CheckBox hidEnabled = (CheckBox) view.findViewById(R.id.hid_enabled_confirm); contactSharing.setText(getString(R.string.bluetooth_pairing_shares_phonebook)); contactSharing.setVisibility( @@ -349,6 +350,12 @@ private View createView() { contactSharing.setChecked(mPairingController.getContactSharingState()); contactSharing.setOnCheckedChangeListener(mPairingController); + hidEnabled.setText(getString(R.string.bluetooth_allow_input_device)); + hidEnabled.setVisibility( + mPairingController.isHidDevice() ? View.VISIBLE : View.GONE); + hidEnabled.setChecked(mPairingController.getHidEnabledState()); + hidEnabled.setOnCheckedChangeListener(mPairingController); + messagePairing.setVisibility(mPairingController.isDisplayPairingKeyVariant() ? View.VISIBLE : View.GONE); if (mPairingController.hasPairingContent()) { From 015059d4db1c7948d6fe878dfbfb1dc18397d9c1 Mon Sep 17 00:00:00 2001 From: Griffin Millender Date: Sat, 13 Jan 2024 21:00:12 -0600 Subject: [PATCH 94/97] More descriptive string --- res/values/strings_ext.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/values/strings_ext.xml b/res/values/strings_ext.xml index 188b4b64e52..5fc7ca8190a 100644 --- a/res/values/strings_ext.xml +++ b/res/values/strings_ext.xml @@ -138,6 +138,6 @@ Native code debugging (ptrace) slightly weakens the app sandbox. Some apps (most View logs - Allow input device + Allow input from this device From 2746585b628adeb6f17b6b0a0b31571036186cfa Mon Sep 17 00:00:00 2001 From: Griffin Millender Date: Sat, 13 Jan 2024 21:10:41 -0600 Subject: [PATCH 95/97] Change input device enabled checkbox to default true --- .../android/settings/bluetooth/BluetoothPairingController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/com/android/settings/bluetooth/BluetoothPairingController.java b/src/com/android/settings/bluetooth/BluetoothPairingController.java index 09802840e66..4208ae64b48 100644 --- a/src/com/android/settings/bluetooth/BluetoothPairingController.java +++ b/src/com/android/settings/bluetooth/BluetoothPairingController.java @@ -79,7 +79,7 @@ public class BluetoothPairingController implements OnCheckedChangeListener, private boolean mIsLeContactSharingEnabled; private boolean mIsLateBonding; private boolean mIsHid = false; - private boolean mIsHidEnabled = false; + private boolean mIsHidEnabled = true; private BluetoothHidHost mBluetoothHidHost; // These callbacks run on the main thread. From cbe290cf606592193a10983e7114b871e66fca5e Mon Sep 17 00:00:00 2001 From: Griffin Millender Date: Sat, 20 Jan 2024 15:27:18 -0600 Subject: [PATCH 96/97] Only set hid connection policy if hid device --- .../settings/bluetooth/BluetoothPairingController.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/com/android/settings/bluetooth/BluetoothPairingController.java b/src/com/android/settings/bluetooth/BluetoothPairingController.java index 4208ae64b48..e2a8e3be1f0 100644 --- a/src/com/android/settings/bluetooth/BluetoothPairingController.java +++ b/src/com/android/settings/bluetooth/BluetoothPairingController.java @@ -271,8 +271,10 @@ public boolean getHidEnabledState() { public void onDialogDismissed(boolean success) { if (success) { - mBluetoothHidHost.setConnectionPolicy(mDevice, - mIsHidEnabled ? CONNECTION_POLICY_ALLOWED : CONNECTION_POLICY_FORBIDDEN); + if (mIsHid) { + mBluetoothHidHost.setConnectionPolicy(mDevice, + mIsHidEnabled ? CONNECTION_POLICY_ALLOWED : CONNECTION_POLICY_FORBIDDEN); + } } } From 61b3149f3b381f3d091c877aaa5c62fc062786e3 Mon Sep 17 00:00:00 2001 From: Griffin Millender Date: Sat, 20 Jan 2024 15:28:29 -0600 Subject: [PATCH 97/97] More descriptive string for bluetooth input device toggle Co-authored-by: Demi Marie Obenour --- res/values/strings_ext.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/values/strings_ext.xml b/res/values/strings_ext.xml index 5fc7ca8190a..c781e487bc9 100644 --- a/res/values/strings_ext.xml +++ b/res/values/strings_ext.xml @@ -138,6 +138,6 @@ Native code debugging (ptrace) slightly weakens the app sandbox. Some apps (most View logs - Allow input from this device + Allow this device to act as a keyboard, mouse, or tablet