diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 2c62ebd684c..177e750c892 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -132,6 +132,7 @@ + diff --git a/res/values/config.xml b/res/values/config.xml index c9cc4556861..c20f08035c2 100644 --- a/res/values/config.xml +++ b/res/values/config.xml @@ -848,4 +848,7 @@ false + + + false diff --git a/res/values/strings.xml b/res/values/strings.xml index ddf69813aa1..c5a938e6f18 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -924,6 +924,10 @@ Require eyes to be open To unlock the phone, your eyes must be open + + + + Always require confirmation @@ -5722,6 +5726,8 @@ Edit accessibility shortcuts Choose your shortcut for %1$s + + To use this, turn on the %1$s shortcut on an accessibility feature\'s page Continue diff --git a/res/xml/accessibility_shortcuts_settings.xml b/res/xml/accessibility_shortcuts_settings.xml index c8070564eb4..18ec9e927ba 100644 --- a/res/xml/accessibility_shortcuts_settings.xml +++ b/res/xml/accessibility_shortcuts_settings.xml @@ -19,7 +19,8 @@ xmlns:settings="http://schemas.android.com/apk/res-auto" android:key="accessibility_shortcuts_settings" android:persistent="false" - android:title="@string/accessibility_shortcuts_settings_title"> + android:title="@string/accessibility_shortcuts_settings_title" + settings:searchable="false"> + settings:controller="com.android.settings.accessibility.HardwareShortcutFromLockscreenPreferenceController"/> diff --git a/src/com/android/settings/accessibility/AccessibilityButtonFragment.java b/src/com/android/settings/accessibility/AccessibilityButtonFragment.java index 60e4bb28fea..116554d735a 100644 --- a/src/com/android/settings/accessibility/AccessibilityButtonFragment.java +++ b/src/com/android/settings/accessibility/AccessibilityButtonFragment.java @@ -16,9 +16,14 @@ package com.android.settings.accessibility; -import android.app.settings.SettingsEnums; -import android.os.Bundle; +import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.SOFTWARE; +import android.app.settings.SettingsEnums; +import android.content.Context; +import android.os.Bundle; +import android.provider.Settings; + +import com.android.internal.accessibility.util.ShortcutUtils; import com.android.settings.R; import com.android.settings.dashboard.DashboardFragment; import com.android.settings.search.BaseSearchIndexProvider; @@ -61,5 +66,13 @@ public class AccessibilityButtonFragment extends DashboardFragment { } public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = - new BaseSearchIndexProvider(R.xml.accessibility_button_settings); + new BaseSearchIndexProvider(R.xml.accessibility_button_settings) { + @Override + protected boolean isPageSearchEnabled(Context context) { + // Page should be unsearchable if there are no active button targets + String targets = Settings.Secure.getStringForUser(context.getContentResolver(), + ShortcutUtils.convertToKey(SOFTWARE), context.getUserId()); + return targets != null && !targets.isEmpty(); + } + }; } diff --git a/src/com/android/settings/accessibility/AccessibilityButtonPreferenceController.java b/src/com/android/settings/accessibility/AccessibilityButtonPreferenceController.java index 68a765c9230..d9ee3cd31f7 100644 --- a/src/com/android/settings/accessibility/AccessibilityButtonPreferenceController.java +++ b/src/com/android/settings/accessibility/AccessibilityButtonPreferenceController.java @@ -16,9 +16,13 @@ package com.android.settings.accessibility; +import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.SOFTWARE; + import android.content.Context; import android.content.res.Resources; +import android.view.accessibility.AccessibilityManager; +import androidx.annotation.NonNull; import androidx.preference.Preference; import androidx.preference.PreferenceScreen; @@ -32,14 +36,39 @@ import java.util.List; * Preference controller for accessibility button preference. */ public class AccessibilityButtonPreferenceController extends BasePreferenceController { - public AccessibilityButtonPreferenceController(Context context, String key) { super(context, key); } @Override public int getAvailabilityStatus() { - return AVAILABLE; + if (!com.android.settings.accessibility.Flags.fixA11ySettingsSearch()) { + return AVAILABLE; + } else { + if (mContext.getSystemService(AccessibilityManager.class) + .getAccessibilityShortcutTargets(SOFTWARE).isEmpty()) { + return DISABLED_DEPENDENT_SETTING; + } else { + return AVAILABLE; + } + } + } + + @Override + public void updateState(@NonNull Preference preference) { + super.updateState(preference); + refreshSummary(preference); + } + + @Override + public @NonNull CharSequence getSummary() { + if (getAvailabilityStatus() == AVAILABLE) { + return ""; + } else { + return mContext.getString( + R.string.accessibility_shortcut_unassigned_setting_unavailable_summary, + AccessibilityUtil.getShortcutSummaryList(mContext, SOFTWARE)); + } } @Override @@ -47,7 +76,6 @@ public class AccessibilityButtonPreferenceController extends BasePreferenceContr super.displayPreference(screen); final Preference preference = screen.findPreference(getPreferenceKey()); preference.setTitle(getPreferenceTitleResource()); - } @Override diff --git a/src/com/android/settings/accessibility/AccessibilityShortcutPreferenceController.java b/src/com/android/settings/accessibility/HardwareShortcutFromLockscreenPreferenceController.java similarity index 58% rename from src/com/android/settings/accessibility/AccessibilityShortcutPreferenceController.java rename to src/com/android/settings/accessibility/HardwareShortcutFromLockscreenPreferenceController.java index d204bb761db..a6d5b7bc7fe 100644 --- a/src/com/android/settings/accessibility/AccessibilityShortcutPreferenceController.java +++ b/src/com/android/settings/accessibility/HardwareShortcutFromLockscreenPreferenceController.java @@ -15,6 +15,7 @@ */ package com.android.settings.accessibility; +import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.HARDWARE; import static com.android.settings.accessibility.AccessibilityUtil.State.OFF; import static com.android.settings.accessibility.AccessibilityUtil.State.ON; @@ -22,16 +23,21 @@ import android.content.ContentResolver; import android.content.Context; import android.os.UserHandle; import android.provider.Settings; +import android.view.accessibility.AccessibilityManager; + +import androidx.annotation.NonNull; +import androidx.preference.Preference; import com.android.settings.R; import com.android.settings.core.TogglePreferenceController; /** - * Settings page for accessibility shortcut + * Setting to allow the hardware shortcut to turn on from the lock screen */ -public class AccessibilityShortcutPreferenceController extends TogglePreferenceController { - - public AccessibilityShortcutPreferenceController(Context context, String preferenceKey) { +public class HardwareShortcutFromLockscreenPreferenceController + extends TogglePreferenceController { + public HardwareShortcutFromLockscreenPreferenceController( + Context context, String preferenceKey) { super(context, preferenceKey); } @@ -56,7 +62,33 @@ public class AccessibilityShortcutPreferenceController extends TogglePreferenceC @Override public int getAvailabilityStatus() { - return AVAILABLE; + if (!com.android.settings.accessibility.Flags.fixA11ySettingsSearch()) { + return AVAILABLE; + } else { + if (mContext.getSystemService(AccessibilityManager.class) + .getAccessibilityShortcutTargets(HARDWARE).isEmpty()) { + return DISABLED_DEPENDENT_SETTING; + } else { + return AVAILABLE; + } + } + } + + @Override + public void updateState(@NonNull Preference preference) { + super.updateState(preference); + refreshSummary(preference); + } + + @Override + public @NonNull CharSequence getSummary() { + if (getAvailabilityStatus() == AVAILABLE) { + return mContext.getString(R.string.accessibility_shortcut_description); + } else { + return mContext.getString( + R.string.accessibility_shortcut_unassigned_setting_unavailable_summary, + AccessibilityUtil.getShortcutSummaryList(mContext, HARDWARE)); + } } @Override diff --git a/src/com/android/settings/biometrics/face/FaceAttentionController.java b/src/com/android/settings/biometrics/face/FaceAttentionController.java new file mode 100644 index 00000000000..f035dfd0719 --- /dev/null +++ b/src/com/android/settings/biometrics/face/FaceAttentionController.java @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2025 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.biometrics.face; + +import static android.hardware.biometrics.BiometricFaceConstants.FEATURE_REQUIRE_ATTENTION; + +import android.content.Context; +import android.hardware.face.FaceManager; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.android.settings.Utils; + +public class FaceAttentionController { + + @Nullable private byte[] mToken; + private FaceManager mFaceManager; + + public interface OnSetAttentionListener { + /** + * Calls when setting attention is completed from FaceManager. + */ + void onSetAttentionCompleted(boolean success); + } + + public interface OnGetAttentionListener { + /** + * Calls when getting attention is completed from FaceManager. + */ + void onGetAttentionCompleted(boolean success, boolean enabled); + } + + @Nullable private OnSetAttentionListener mSetListener; + @Nullable private OnGetAttentionListener mGetListener; + + private final FaceManager.SetFeatureCallback mSetFeatureCallback = + new FaceManager.SetFeatureCallback() { + @Override + public void onCompleted(boolean success, int feature) { + if (feature == FEATURE_REQUIRE_ATTENTION) { + if (mSetListener != null) { + mSetListener.onSetAttentionCompleted(success); + } + } + } + }; + + private final FaceManager.GetFeatureCallback mGetFeatureCallback = + new FaceManager.GetFeatureCallback() { + @Override + public void onCompleted( + boolean success, @NonNull int[] features, @NonNull boolean[] featureState) { + boolean requireAttentionEnabled = false; + for (int i = 0; i < features.length; i++) { + if (features[i] == FEATURE_REQUIRE_ATTENTION) { + requireAttentionEnabled = featureState[i]; + } + } + if (mGetListener != null) { + mGetListener.onGetAttentionCompleted(success, requireAttentionEnabled); + } + } + }; + + public FaceAttentionController(@NonNull Context context) { + mFaceManager = Utils.getFaceManagerOrNull(context); + } + + /** + * Set the challenge token + */ + public void setToken(@Nullable byte[] token) { + mToken = token; + } + + /** + * Get the gaze status + */ + public void getAttentionStatus(int userId, + @Nullable OnGetAttentionListener listener) { + mGetListener = listener; + mFaceManager.getFeature(userId, FEATURE_REQUIRE_ATTENTION, mGetFeatureCallback); + } + + /** + * Set the gaze status + */ + public void setAttentionStatus( + int userId, boolean enabled, @Nullable OnSetAttentionListener listener) { + mSetListener = listener; + mFaceManager.setFeature(userId, FEATURE_REQUIRE_ATTENTION, enabled, mToken, + mSetFeatureCallback); + } +} diff --git a/src/com/android/settings/biometrics/face/FaceEnrollEducation.java b/src/com/android/settings/biometrics/face/FaceEnrollEducation.java index 6862bc921d7..7b0b8ef0f56 100644 --- a/src/com/android/settings/biometrics/face/FaceEnrollEducation.java +++ b/src/com/android/settings/biometrics/face/FaceEnrollEducation.java @@ -69,6 +69,7 @@ public class FaceEnrollEducation extends BiometricEnrollBase { private View mIllustrationAccessibility; private Intent mResultIntent; private boolean mAccessibilityEnabled; + protected Intent mExtraInfoIntent; private final CompoundButton.OnCheckedChangeListener mSwitchDiversityListener = new CompoundButton.OnCheckedChangeListener() { @@ -171,12 +172,7 @@ public class FaceEnrollEducation extends BiometricEnrollBase { mFooterBarMixin.setPrimaryButton(footerButton); final Button accessibilityButton = findViewById(R.id.accessibility_button); - accessibilityButton.setOnClickListener(view -> { - mSwitchDiversity.setChecked(true); - accessibilityButton.setVisibility(View.GONE); - mSwitchDiversity.setVisibility(View.VISIBLE); - mSwitchDiversity.addOnLayoutChangeListener(mSwitchDiversityOnLayoutChangeListener); - }); + accessibilityButton.setOnClickListener(this::onAccessibilityButtonClicked); mSwitchDiversity = findViewById(R.id.toggle_diversity); mSwitchDiversity.setListener(mSwitchDiversityListener); @@ -263,6 +259,9 @@ public class FaceEnrollEducation extends BiometricEnrollBase { if (mResultIntent != null) { intent.putExtras(mResultIntent); } + if (mExtraInfoIntent != null) { + intent.putExtras(mExtraInfoIntent); + } intent.putExtra(EXTRA_KEY_REQUIRE_DIVERSITY, !mSwitchDiversity.isChecked()); intent.putExtra(BiometricUtils.EXTRA_ENROLL_REASON, @@ -282,6 +281,13 @@ public class FaceEnrollEducation extends BiometricEnrollBase { } + protected void onAccessibilityButtonClicked(View view) { + mSwitchDiversity.setChecked(true); + view.setVisibility(View.GONE); + mSwitchDiversity.setVisibility(View.VISIBLE); + mSwitchDiversity.addOnLayoutChangeListener(mSwitchDiversityOnLayoutChangeListener); + } + protected void onSkipButtonClick(View view) { if (!BiometricUtils.tryStartingNextBiometricEnroll(this, ENROLL_NEXT_BIOMETRIC_REQUEST, "edu_skip")) { diff --git a/src/com/android/settings/biometrics/face/FaceSettingsAttentionPreferenceController.java b/src/com/android/settings/biometrics/face/FaceSettingsAttentionPreferenceController.java index 71c46787261..c7e2141c53a 100644 --- a/src/com/android/settings/biometrics/face/FaceSettingsAttentionPreferenceController.java +++ b/src/com/android/settings/biometrics/face/FaceSettingsAttentionPreferenceController.java @@ -16,12 +16,8 @@ package com.android.settings.biometrics.face; -import static android.hardware.biometrics.BiometricFaceConstants.FEATURE_REQUIRE_ATTENTION; - import android.content.Context; import android.hardware.face.FaceManager; -import android.hardware.face.FaceManager.GetFeatureCallback; -import android.hardware.face.FaceManager.SetFeatureCallback; import android.provider.Settings; import androidx.annotation.Nullable; @@ -31,6 +27,7 @@ import androidx.preference.TwoStatePreference; import com.android.settings.R; import com.android.settings.Utils; +import com.android.settings.flags.Flags; /** * Preference controller that manages the ability to use face authentication with/without @@ -40,14 +37,13 @@ public class FaceSettingsAttentionPreferenceController extends FaceSettingsPrefe public static final String KEY = "security_settings_face_require_attention"; - private byte[] mToken; - private FaceManager mFaceManager; private TwoStatePreference mPreference; + private boolean mGazeEnabled; - private final SetFeatureCallback mSetFeatureCallback = new SetFeatureCallback() { - @Override - public void onCompleted(boolean success, int feature) { - if (feature == FEATURE_REQUIRE_ATTENTION) { + private FaceAttentionController mFaceAttentionController; + + private final FaceAttentionController.OnSetAttentionListener mSetAttentionListener = + (success) -> { mPreference.setEnabled(true); if (!success) { mPreference.setChecked(!mPreference.isChecked()); @@ -56,31 +52,23 @@ public class FaceSettingsAttentionPreferenceController extends FaceSettingsPrefe Settings.Secure.FACE_UNLOCK_ATTENTION_REQUIRED, mPreference.isChecked() ? 1 : 0, getUserId()); } - } - } - }; + }; - private final GetFeatureCallback mGetFeatureCallback = new GetFeatureCallback() { - @Override - public void onCompleted(boolean success, int[] features, boolean[] featureState) { - boolean requireAttentionEnabled = false; - for (int i = 0; i < features.length; i++) { - if (features[i] == FEATURE_REQUIRE_ATTENTION) { - requireAttentionEnabled = featureState[i]; + private final FaceAttentionController.OnGetAttentionListener mOnGetAttentionListener = + (success, requireAttentionEnabled) -> { + mPreference.setChecked(requireAttentionEnabled); + if (getRestrictingAdmin() != null) { + mPreference.setEnabled(false); + } else { + mPreference.setEnabled(success); } - } - mPreference.setChecked(requireAttentionEnabled); - if (getRestrictingAdmin() != null) { - mPreference.setEnabled(false); - } else { - mPreference.setEnabled(success); - } - } - }; + }; public FaceSettingsAttentionPreferenceController(Context context, String preferenceKey) { super(context, preferenceKey); - mFaceManager = Utils.getFaceManagerOrNull(context); + mFaceAttentionController = new FaceAttentionController(context); + mGazeEnabled = context.getResources().getBoolean(R.bool.config_gazeEnabled) + && Flags.biometricsOnboardingEducation(); } public FaceSettingsAttentionPreferenceController(Context context) { @@ -88,7 +76,9 @@ public class FaceSettingsAttentionPreferenceController extends FaceSettingsPrefe } public void setToken(byte[] token) { - mToken = token; + if (mFaceAttentionController != null) { + mFaceAttentionController.setToken(token); + } } /** @@ -109,6 +99,11 @@ public class FaceSettingsAttentionPreferenceController extends FaceSettingsPrefe if (Utils.isPrivateProfile(getUserId(), mContext)) { preference.setSummary(mContext.getString( R.string.private_space_face_settings_require_attention_details)); + } else if (mGazeEnabled) { + preference.setTitle(mContext.getString( + R.string.security_settings_face_settings_gaze)); + preference.setSummary(mContext.getString( + R.string.security_settings_face_settings_gaze_details)); } } @@ -119,8 +114,7 @@ public class FaceSettingsAttentionPreferenceController extends FaceSettingsPrefe } // Set to disabled until we know the true value. mPreference.setEnabled(false); - mFaceManager.getFeature(getUserId(), FEATURE_REQUIRE_ATTENTION, - mGetFeatureCallback); + mFaceAttentionController.getAttentionStatus(getUserId(), mOnGetAttentionListener); // Ideally returns a cached value. return true; @@ -131,9 +125,7 @@ public class FaceSettingsAttentionPreferenceController extends FaceSettingsPrefe // Optimistically update state and set to disabled until we know it succeeded. mPreference.setEnabled(false); mPreference.setChecked(isChecked); - - mFaceManager.setFeature(getUserId(), FEATURE_REQUIRE_ATTENTION, - isChecked, mToken, mSetFeatureCallback); + mFaceAttentionController.setAttentionStatus(getUserId(), isChecked, mSetAttentionListener); return true; } diff --git a/src/com/android/settings/development/DesktopModePreferenceController.java b/src/com/android/settings/development/DesktopModePreferenceController.java index 8012d31b9f6..4c6da1ee1cd 100644 --- a/src/com/android/settings/development/DesktopModePreferenceController.java +++ b/src/com/android/settings/development/DesktopModePreferenceController.java @@ -89,7 +89,7 @@ public class DesktopModePreferenceController extends DeveloperOptionsPreferenceC final boolean shouldDevOptionBeEnabled = switch (toggleOverride) { case OVERRIDE_OFF -> false; case OVERRIDE_ON -> true; - case OVERRIDE_UNSET -> DesktopModeStatus.shouldDevOptionBeEnabledByDefault(); + case OVERRIDE_UNSET -> DesktopModeStatus.shouldDevOptionBeEnabledByDefault(mContext); }; ((TwoStatePreference) mPreference).setChecked(shouldDevOptionBeEnabled); } diff --git a/src/com/android/settings/network/CellularSecurityPreferenceController.java b/src/com/android/settings/network/CellularSecurityPreferenceController.java index a184553c0f3..087cfaf840a 100644 --- a/src/com/android/settings/network/CellularSecurityPreferenceController.java +++ b/src/com/android/settings/network/CellularSecurityPreferenceController.java @@ -23,6 +23,7 @@ import android.content.pm.PackageManager; import android.os.Build; import android.os.Bundle; import android.safetycenter.SafetyCenterManager; +import android.safetycenter.SafetySourceData; import android.telephony.SubscriptionInfo; import android.telephony.TelephonyManager; import android.text.TextUtils; @@ -48,6 +49,7 @@ import java.util.List; public class CellularSecurityPreferenceController extends BasePreferenceController { private static final String LOG_TAG = "CellularSecurityPreferenceController"; + private static final String SAFETY_SOURCE_ID = "AndroidCellularNetworkSecurity"; private @Nullable TelephonyManager mTelephonyManager; @@ -72,7 +74,6 @@ public class CellularSecurityPreferenceController extends BasePreferenceControll if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEPHONY) || !Flags.enableIdentifierDisclosureTransparencyUnsolEvents() || !Flags.enableModemCipherTransparencyUnsolEvents() - || !Flags.enableIdentifierDisclosureTransparency() || !Flags.enableModemCipherTransparency()) { return UNSUPPORTED_ON_DEVICE; } @@ -134,13 +135,30 @@ public class CellularSecurityPreferenceController extends BasePreferenceControll if (!TextUtils.equals(preference.getKey(), getPreferenceKey())) { return super.handlePreferenceTreeClick(preference); } - boolean isSafetyCenterSupported = isSafetyCenterSupported(); - if (isSafetyCenterSupported && areNotificationsEnabled()) { + if (!isSafetyCenterSupported()) { + // Realistically, it's unlikely to end up in handlePreferenceTreeClick with SafetyCenter + // being not supported on the device. + return false; + } + // Need to check that both Safety Center is available on device, and also that the HALs are + // enabled before showing the Safety Center UI. Otherwise, we need to take them to the page + // where the HALs can be enabled. + SafetyCenterManager safetyCenterManager = mContext.getSystemService( + SafetyCenterManager.class); + SafetySourceData data = null; + if (safetyCenterManager.isSafetyCenterEnabled()) { + data = safetyCenterManager.getSafetySourceData(SAFETY_SOURCE_ID); + } + // Can only redirect to SafetyCenter if it has received data via the SafetySource, as + // SafetyCenter doesn't support redirecting to a specific page associated with a source + // if it hasn't received data from that source. See b/373942609 for details. + if (data != null && areNotificationsEnabled()) { Intent safetyCenterIntent = new Intent(Intent.ACTION_SAFETY_CENTER); safetyCenterIntent.putExtra(SafetyCenterManager.EXTRA_SAFETY_SOURCES_GROUP_ID, "AndroidCellularNetworkSecuritySources"); mContext.startActivity(safetyCenterIntent); } else { + Log.v(LOG_TAG, "Hardware APIs not enabled, or data source is null."); final Bundle bundle = new Bundle(); bundle.putString(CellularSecuritySettingsFragment.KEY_CELLULAR_SECURITY_PREFERENCE, ""); diff --git a/src/com/android/settings/network/telephony/CellularSecurityNotificationsDividerController.java b/src/com/android/settings/network/telephony/CellularSecurityNotificationsDividerController.java index 131882704f5..51d91a48a89 100644 --- a/src/com/android/settings/network/telephony/CellularSecurityNotificationsDividerController.java +++ b/src/com/android/settings/network/telephony/CellularSecurityNotificationsDividerController.java @@ -62,7 +62,6 @@ public class CellularSecurityNotificationsDividerController extends public int getAvailabilityStatus() { if (!Flags.enableIdentifierDisclosureTransparencyUnsolEvents() || !Flags.enableModemCipherTransparencyUnsolEvents() - || !Flags.enableIdentifierDisclosureTransparency() || !Flags.enableModemCipherTransparency()) { return UNSUPPORTED_ON_DEVICE; } diff --git a/src/com/android/settings/network/telephony/CellularSecurityNotificationsPreferenceController.java b/src/com/android/settings/network/telephony/CellularSecurityNotificationsPreferenceController.java index 4e2d285b8d5..17aca091b73 100644 --- a/src/com/android/settings/network/telephony/CellularSecurityNotificationsPreferenceController.java +++ b/src/com/android/settings/network/telephony/CellularSecurityNotificationsPreferenceController.java @@ -180,7 +180,6 @@ public class CellularSecurityNotificationsPreferenceController extends private boolean areFlagsEnabled() { if (!Flags.enableIdentifierDisclosureTransparencyUnsolEvents() || !Flags.enableModemCipherTransparencyUnsolEvents() - || !Flags.enableIdentifierDisclosureTransparency() || !Flags.enableModemCipherTransparency()) { return false; } diff --git a/tests/robotests/src/com/android/settings/accessibility/AccessibilityButtonFragmentTest.java b/tests/robotests/src/com/android/settings/accessibility/AccessibilityButtonFragmentTest.java index 94312a60eee..386463a5666 100644 --- a/tests/robotests/src/com/android/settings/accessibility/AccessibilityButtonFragmentTest.java +++ b/tests/robotests/src/com/android/settings/accessibility/AccessibilityButtonFragmentTest.java @@ -19,6 +19,8 @@ package com.android.settings.accessibility; import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_2BUTTON; import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL; +import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.SOFTWARE; + import static com.google.common.truth.Truth.assertThat; import static org.mockito.Mockito.spy; @@ -39,6 +41,7 @@ import androidx.preference.PreferenceManager; import androidx.preference.PreferenceScreen; import androidx.test.core.app.ApplicationProvider; +import com.android.internal.accessibility.util.ShortcutUtils; import com.android.settings.R; import com.android.settings.testutils.XmlTestUtils; import com.android.settings.testutils.shadow.ShadowFragment; @@ -132,6 +135,7 @@ public class AccessibilityButtonFragmentTest { } @Test + @DisableFlags(com.android.settings.accessibility.Flags.FLAG_FIX_A11Y_SETTINGS_SEARCH) public void getNonIndexableKeys_existInXmlLayout() { final List niks = AccessibilityButtonFragment.SEARCH_INDEX_DATA_PROVIDER .getNonIndexableKeys(mContext); @@ -139,7 +143,38 @@ public class AccessibilityButtonFragmentTest { XmlTestUtils.getKeysFromPreferenceXml(mContext, R.xml.accessibility_button_settings); - assertThat(keys).containsAtLeastElementsIn(niks); + assertThat(keys).isNotNull(); + assertThat(niks).containsAtLeastElementsIn(keys); + } + + @Test + @EnableFlags(com.android.settings.accessibility.Flags.FLAG_FIX_A11Y_SETTINGS_SEARCH) + public void getNonIndexableKeys_noTargets_doesNotExistInXmlLayout() { + Settings.Secure.putStringForUser(mContext.getContentResolver(), + ShortcutUtils.convertToKey(SOFTWARE), "", mContext.getUserId()); + final List niks = AccessibilityButtonFragment.SEARCH_INDEX_DATA_PROVIDER + .getNonIndexableKeys(mContext); + final List keys = + XmlTestUtils.getKeysFromPreferenceXml(mContext, + R.xml.accessibility_button_settings); + + assertThat(keys).isNotNull(); + assertThat(niks).containsAtLeastElementsIn(keys); + } + + @Test + @EnableFlags(com.android.settings.accessibility.Flags.FLAG_FIX_A11Y_SETTINGS_SEARCH) + public void getNonIndexableKeys_hasTargets_expectedKeys() { + Settings.Secure.putStringForUser(mContext.getContentResolver(), + ShortcutUtils.convertToKey(SOFTWARE), "Foo", mContext.getUserId()); + final List niks = AccessibilityButtonFragment.SEARCH_INDEX_DATA_PROVIDER + .getNonIndexableKeys(mContext); + + // Some keys should show up anyway, as they're flagged as unsearchable in the xml. + assertThat(niks).containsAtLeast( + "accessibility_button_preview", + "accessibility_button_footer", + "accessibility_button_or_gesture"); } private static class TestAccessibilityButtonFragment extends AccessibilityButtonFragment { diff --git a/tests/robotests/src/com/android/settings/accessibility/AccessibilityButtonPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/AccessibilityButtonPreferenceControllerTest.java index 85aa77c1ab8..e5169cd0082 100644 --- a/tests/robotests/src/com/android/settings/accessibility/AccessibilityButtonPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/accessibility/AccessibilityButtonPreferenceControllerTest.java @@ -20,6 +20,10 @@ import static android.provider.Settings.Secure.NAVIGATION_MODE; import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_2BUTTON; import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL; +import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.SOFTWARE; +import static com.android.settings.core.BasePreferenceController.AVAILABLE; +import static com.android.settings.core.BasePreferenceController.DISABLED_DEPENDENT_SETTING; + import static com.google.common.truth.Truth.assertThat; import static org.mockito.Mockito.when; @@ -31,12 +35,15 @@ import android.platform.test.annotations.EnableFlags; import android.platform.test.flag.junit.SetFlagsRule; import android.provider.Flags; import android.provider.Settings; +import android.view.accessibility.AccessibilityManager; import androidx.preference.Preference; import androidx.preference.PreferenceScreen; import androidx.test.core.app.ApplicationProvider; import com.android.settings.R; +import com.android.settings.testutils.shadow.SettingsShadowResources; +import com.android.settings.testutils.shadow.ShadowAccessibilityManager; import com.android.settingslib.search.SearchIndexableRaw; import org.junit.Before; @@ -48,11 +55,17 @@ import org.mockito.Spy; import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; import org.robolectric.RobolectricTestRunner; +import org.robolectric.annotation.Config; +import org.robolectric.shadow.api.Shadow; import java.util.ArrayList; import java.util.List; /** Tests for {@link AccessibilityButtonPreferenceController}. */ +@Config(shadows = { + SettingsShadowResources.class, + com.android.settings.testutils.shadow.ShadowAccessibilityManager.class +}) @RunWith(RobolectricTestRunner.class) public class AccessibilityButtonPreferenceControllerTest { @@ -68,9 +81,12 @@ public class AccessibilityButtonPreferenceControllerTest { private PreferenceScreen mScreen; private Preference mPreference; private AccessibilityButtonPreferenceController mController; + private ShadowAccessibilityManager mShadowAccessibilityManager; @Before public void setUp() { + mShadowAccessibilityManager = Shadow.extract( + mContext.getSystemService(AccessibilityManager.class)); mController = new AccessibilityButtonPreferenceController(mContext, "test_key"); mPreference = new Preference(mContext); mPreference.setKey("test_key"); @@ -163,4 +179,20 @@ public class AccessibilityButtonPreferenceControllerTest { assertThat(raw.screenTitle).isEqualTo( mResources.getString(R.string.accessibility_shortcuts_settings_title)); } + + @Test + @EnableFlags(com.android.settings.accessibility.Flags.FLAG_FIX_A11Y_SETTINGS_SEARCH) + public void getAvailabilityStatus_settingEmpty_disabled() { + mShadowAccessibilityManager.setAccessibilityShortcutTargets(SOFTWARE, List.of()); + + assertThat(mController.getAvailabilityStatus()).isEqualTo(DISABLED_DEPENDENT_SETTING); + } + + @Test + @EnableFlags(com.android.settings.accessibility.Flags.FLAG_FIX_A11Y_SETTINGS_SEARCH) + public void getAvailabilityStatus_settingNotEmpty_available() { + mShadowAccessibilityManager.setAccessibilityShortcutTargets(SOFTWARE, List.of("Foo")); + + assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE); + } } diff --git a/tests/unit/src/com/android/settings/accessibility/AccessibilityShortcutPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/HardwareShortcutFromLockscreenPreferenceControllerTest.java similarity index 56% rename from tests/unit/src/com/android/settings/accessibility/AccessibilityShortcutPreferenceControllerTest.java rename to tests/robotests/src/com/android/settings/accessibility/HardwareShortcutFromLockscreenPreferenceControllerTest.java index 7d903ee01a4..30541a6a2b6 100644 --- a/tests/unit/src/com/android/settings/accessibility/AccessibilityShortcutPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/accessibility/HardwareShortcutFromLockscreenPreferenceControllerTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020 The Android Open Source Project + * Copyright (C) 2024 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. @@ -16,36 +16,57 @@ package com.android.settings.accessibility; +import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.HARDWARE; import static com.android.settings.accessibility.AccessibilityUtil.State.OFF; import static com.android.settings.accessibility.AccessibilityUtil.State.ON; - -import androidx.test.core.app.ApplicationProvider; -import androidx.test.ext.junit.runners.AndroidJUnit4; +import static com.android.settings.core.BasePreferenceController.AVAILABLE; +import static com.android.settings.core.BasePreferenceController.DISABLED_DEPENDENT_SETTING; import static com.google.common.truth.Truth.assertThat; import android.content.Context; import android.os.UserHandle; +import android.platform.test.annotations.EnableFlags; +import android.platform.test.flag.junit.SetFlagsRule; import android.provider.Settings; +import android.view.accessibility.AccessibilityManager; import androidx.preference.SwitchPreference; +import androidx.test.core.app.ApplicationProvider; + +import com.android.settings.testutils.shadow.SettingsShadowResources; +import com.android.settings.testutils.shadow.ShadowAccessibilityManager; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.annotation.Config; +import org.robolectric.shadow.api.Shadow; -@RunWith(AndroidJUnit4.class) -public class AccessibilityShortcutPreferenceControllerTest { +import java.util.List; - private Context mContext; +@Config(shadows = { + SettingsShadowResources.class, + com.android.settings.testutils.shadow.ShadowAccessibilityManager.class +}) +@RunWith(RobolectricTestRunner.class) +public class HardwareShortcutFromLockscreenPreferenceControllerTest { + @Rule + public SetFlagsRule mSetFlagsRule = new SetFlagsRule(); + + private Context mContext = ApplicationProvider.getApplicationContext(); private SwitchPreference mPreference; - private AccessibilityShortcutPreferenceController mController; + private HardwareShortcutFromLockscreenPreferenceController mController; + private ShadowAccessibilityManager mShadowAccessibilityManager; @Before public void setUp() { - mContext = ApplicationProvider.getApplicationContext(); + mShadowAccessibilityManager = Shadow.extract( + mContext.getSystemService(AccessibilityManager.class)); mPreference = new SwitchPreference(mContext); - mController = new AccessibilityShortcutPreferenceController(mContext, + mController = new HardwareShortcutFromLockscreenPreferenceController(mContext, "accessibility_shortcut_preference"); } @@ -89,4 +110,20 @@ public class AccessibilityShortcutPreferenceControllerTest { Settings.Secure.ACCESSIBILITY_SHORTCUT_ON_LOCK_SCREEN, ON, UserHandle.USER_CURRENT)).isEqualTo(OFF); } + + @Test + @EnableFlags(Flags.FLAG_FIX_A11Y_SETTINGS_SEARCH) + public void getAvailabilityStatus_settingEmpty_disabled() { + mShadowAccessibilityManager.setAccessibilityShortcutTargets(HARDWARE, List.of()); + + assertThat(mController.getAvailabilityStatus()).isEqualTo(DISABLED_DEPENDENT_SETTING); + } + + @Test + @EnableFlags(Flags.FLAG_FIX_A11Y_SETTINGS_SEARCH) + public void getAvailabilityStatus_settingNotEmpty_available() { + mShadowAccessibilityManager.setAccessibilityShortcutTargets(HARDWARE, List.of("Foo")); + + assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE); + } } diff --git a/tests/robotests/src/com/android/settings/display/ColorContrastFragmentTest.java b/tests/robotests/src/com/android/settings/display/ColorContrastFragmentTest.java index 47a7363b531..1e6827ba9f3 100644 --- a/tests/robotests/src/com/android/settings/display/ColorContrastFragmentTest.java +++ b/tests/robotests/src/com/android/settings/display/ColorContrastFragmentTest.java @@ -28,7 +28,6 @@ import android.content.Context; import androidx.test.core.app.ApplicationProvider; import com.android.settings.R; -import com.android.settings.accessibility.ShortcutsSettingsFragment; import com.android.settings.testutils.XmlTestUtils; import org.junit.Before; @@ -79,7 +78,7 @@ public class ColorContrastFragmentTest { @Test public void getNonIndexableKeys_existInXmlLayout() { final List niks = - ShortcutsSettingsFragment.SEARCH_INDEX_DATA_PROVIDER + ColorContrastFragment.SEARCH_INDEX_DATA_PROVIDER .getNonIndexableKeys(mContext); final List keys = XmlTestUtils.getKeysFromPreferenceXml(mContext, diff --git a/tests/unit/src/com/android/settings/network/CellularSecurityPreferenceControllerTest.java b/tests/unit/src/com/android/settings/network/CellularSecurityPreferenceControllerTest.java index 7f05913cd82..03f6bcdb238 100644 --- a/tests/unit/src/com/android/settings/network/CellularSecurityPreferenceControllerTest.java +++ b/tests/unit/src/com/android/settings/network/CellularSecurityPreferenceControllerTest.java @@ -26,7 +26,6 @@ import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.content.Context; @@ -50,7 +49,6 @@ import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; @@ -148,36 +146,17 @@ public final class CellularSecurityPreferenceControllerTest { assertThat(mController.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE); } - @Test - public void handlePreferenceTreeClick_safetyCenterSupported_shouldRedirectToSafetyCenter() { - final ArgumentCaptor intentCaptor = ArgumentCaptor.forClass(Intent.class); - - doReturn(true).when(mTelephonyManager).isNullCipherNotificationsEnabled(); - doReturn(true).when(mTelephonyManager) - .isCellularIdentifierDisclosureNotificationsEnabled(); - doReturn(true).when(mTelephonyManager).isNullCipherAndIntegrityPreferenceEnabled(); - boolean prefHandled = mController.handlePreferenceTreeClick(mPreference); - - assertThat(prefHandled).isTrue(); - verify(mContext).startActivity(intentCaptor.capture()); - assertThat(intentCaptor.getValue().getAction()).isEqualTo(Intent.ACTION_SAFETY_CENTER); - } - private void enableFlags(boolean enabled) { if (enabled) { mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_MODEM_CIPHER_TRANSPARENCY_UNSOL_EVENTS); mSetFlagsRule.enableFlags( Flags.FLAG_ENABLE_IDENTIFIER_DISCLOSURE_TRANSPARENCY_UNSOL_EVENTS); mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_MODEM_CIPHER_TRANSPARENCY); - mSetFlagsRule.enableFlags( - Flags.FLAG_ENABLE_IDENTIFIER_DISCLOSURE_TRANSPARENCY); } else { mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_MODEM_CIPHER_TRANSPARENCY_UNSOL_EVENTS); mSetFlagsRule.disableFlags( Flags.FLAG_ENABLE_IDENTIFIER_DISCLOSURE_TRANSPARENCY_UNSOL_EVENTS); mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_MODEM_CIPHER_TRANSPARENCY); - mSetFlagsRule.disableFlags( - Flags.FLAG_ENABLE_IDENTIFIER_DISCLOSURE_TRANSPARENCY); } } } diff --git a/tests/unit/src/com/android/settings/network/telephony/CellularSecurityNotificationsDividerControllerTest.java b/tests/unit/src/com/android/settings/network/telephony/CellularSecurityNotificationsDividerControllerTest.java index 4e2351f1c7d..998f82ef9eb 100644 --- a/tests/unit/src/com/android/settings/network/telephony/CellularSecurityNotificationsDividerControllerTest.java +++ b/tests/unit/src/com/android/settings/network/telephony/CellularSecurityNotificationsDividerControllerTest.java @@ -129,15 +129,11 @@ public class CellularSecurityNotificationsDividerControllerTest { mSetFlagsRule.enableFlags( Flags.FLAG_ENABLE_IDENTIFIER_DISCLOSURE_TRANSPARENCY_UNSOL_EVENTS); mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_MODEM_CIPHER_TRANSPARENCY); - mSetFlagsRule.enableFlags( - Flags.FLAG_ENABLE_IDENTIFIER_DISCLOSURE_TRANSPARENCY); } else { mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_MODEM_CIPHER_TRANSPARENCY_UNSOL_EVENTS); mSetFlagsRule.disableFlags( Flags.FLAG_ENABLE_IDENTIFIER_DISCLOSURE_TRANSPARENCY_UNSOL_EVENTS); mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_MODEM_CIPHER_TRANSPARENCY); - mSetFlagsRule.disableFlags( - Flags.FLAG_ENABLE_IDENTIFIER_DISCLOSURE_TRANSPARENCY); } } } diff --git a/tests/unit/src/com/android/settings/network/telephony/CellularSecurityNotificationsPreferenceControllerTest.java b/tests/unit/src/com/android/settings/network/telephony/CellularSecurityNotificationsPreferenceControllerTest.java index 8a72bd5fae3..c520918c665 100644 --- a/tests/unit/src/com/android/settings/network/telephony/CellularSecurityNotificationsPreferenceControllerTest.java +++ b/tests/unit/src/com/android/settings/network/telephony/CellularSecurityNotificationsPreferenceControllerTest.java @@ -233,15 +233,11 @@ public class CellularSecurityNotificationsPreferenceControllerTest { mSetFlagsRule.enableFlags( Flags.FLAG_ENABLE_IDENTIFIER_DISCLOSURE_TRANSPARENCY_UNSOL_EVENTS); mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_MODEM_CIPHER_TRANSPARENCY); - mSetFlagsRule.enableFlags( - Flags.FLAG_ENABLE_IDENTIFIER_DISCLOSURE_TRANSPARENCY); } else { mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_MODEM_CIPHER_TRANSPARENCY_UNSOL_EVENTS); mSetFlagsRule.disableFlags( Flags.FLAG_ENABLE_IDENTIFIER_DISCLOSURE_TRANSPARENCY_UNSOL_EVENTS); mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_MODEM_CIPHER_TRANSPARENCY); - mSetFlagsRule.disableFlags( - Flags.FLAG_ENABLE_IDENTIFIER_DISCLOSURE_TRANSPARENCY); } } }