Snap for 9957928 from 4d5ac5a89f to udc-release

Change-Id: I51bcde837f4e9b986fdc3958ab4544c41c2c85f2
This commit is contained in:
Android Build Coastguard Worker
2023-04-18 01:37:39 +00:00
13 changed files with 526 additions and 89 deletions

View File

@@ -716,4 +716,9 @@
<string name="battery_tip_incompatible_charging_message" product="default">Battery charging slowly or won\'t charge. Check if the cable and power adapter work with your phone</string>
<string name="battery_tip_incompatible_charging_message" product="device">Battery charging slowly or won\'t charge. Check if the cable and power adapter work with your device</string>
<string name="battery_tip_incompatible_charging_message" product="tablet">Battery charging slowly or won\'t charge. Check if the cable and power adapter work with your tablet</string>
<!-- Description for using device controls feature with a locked phone [CHAR LIMIT=NONE] -->
<string name="lockscreen_trivial_controls_summary" product="default">Without unlocking your phone</string>
<!-- Description for using device controls feature with a locked tablet [CHAR LIMIT=NONE] -->
<string name="lockscreen_trivial_controls_summary" product="tabled">Without unlocking your tablet</string>
</resources>

View File

@@ -71,7 +71,7 @@
android:id="@+id/card_preference_buttons"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:layout_marginTop="10dp"
android:layout_below="@android:id/summary"
android:visibility="gone">
<Button
@@ -105,4 +105,4 @@
android:paddingEnd="0dp"
android:orientation="vertical"/>
</LinearLayout>
</LinearLayout>

View File

@@ -746,6 +746,8 @@
<!-- Fingerprint enrollment and settings --><skip />
<!-- Note: Update FingerprintEnrollParentalConsent.CONSENT_STRING_RESOURCES when any _consent_ strings are added or removed. -->
<!-- Title shown for choose lock options [CHAR LIMIT=22] -->
<string name="security_settings_fingerprint">Fingerprint</string>
<!-- Title shown for menu item that launches fingerprint settings or enrollment [CHAR LIMIT=22] -->
<string name="security_settings_fingerprint_preference_title">Fingerprint</string>
<!-- Title for a category shown for the fingerprint settings page, followed by items that the user can toggle on/off to require/disable. [CHAR LIMIT=50] -->
@@ -10282,13 +10284,10 @@
<string name="credman_confirmation_message">Saved info like addresses or payment methods won\'t be filled in when you sign in. To keep your saved info filled in, set enable a password, passkey and data/or service.</string>
<!-- Title of the warning dialog for enabling the credential provider. [CHAR_LIMIT=NONE] -->
<string name="credman_enable_confirmation_message_title">Turn on %1$s\?</string>
<string name="credman_enable_confirmation_message_title">Use %1$s\?</string>
<!-- Message of the warning dialog for enabling the credential provider. [CHAR_LIMIT=NONE] -->
<string name="credman_enable_confirmation_message">Saved info like addresses or payment methods will be shared with this provider.</string>
<!-- Positive button to turn on credential manager provider (confirmation). [CHAR LIMIT=60] -->
<string name="credman_enable_confirmation_message_positive_button">Turn on</string>
<string name="credman_enable_confirmation_message">%1$s uses what\'s on your screen to determine what can be autofilled.</string>
<!-- Title of the error dialog when too many credential providers are selected. [CHAR_LIMIT=NONE] -->
<string name="credman_error_message_title">Passwords, passkeys and data services limit</string>
@@ -11238,11 +11237,9 @@
<!-- Device controls toggle name [CHAR LIMIT=60] -->
<string name="lockscreen_privacy_controls_setting_toggle">Show device controls</string>
<!-- Device controls summary [CHAR LIMIT=NONE] -->
<string name="lockscreen_privacy_controls_summary">Show controls for external devices from the lock screen</string>
<string name="lockscreen_privacy_controls_summary">From the lockscreen</string>
<!-- Trivial Device controls toggle name [CHAR LIMIT=60] -->
<string name="lockscreen_trivial_controls_setting_toggle">Control from locked device</string>
<!-- Trivial Device controls summary [CHAR LIMIT=NONE] -->
<string name="lockscreen_trivial_controls_summary">Control external devices without unlocking your phone or tablet if allowed by the device controls app</string>
<string name="lockscreen_trivial_controls_setting_toggle">Use device controls</string>
<!-- Trivial Device disabled controls summary [CHAR LIMIT=NONE] -->
<string name="lockscreen_trivial_disabled_controls_summary">To use, first turn on \u0022Show device controls\u0022</string>
<!-- Lockscreen double-line clock summary [CHAR LIMIT=NONE] -->

View File

@@ -153,8 +153,7 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl
}
final String action = launchIntent.getAction();
final boolean isCredProviderAction =
TextUtils.equals(action, PRIMARY_INTENT);
final boolean isCredProviderAction = TextUtils.equals(action, PRIMARY_INTENT);
final boolean isExistingAction = TextUtils.equals(action, ALTERNATE_INTENT);
final boolean isValid = isCredProviderAction || isExistingAction;
@@ -226,7 +225,8 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl
}
NewProviderConfirmationDialogFragment fragment =
newNewProviderConfirmationDialogFragment(serviceInfo.packageName, appName);
newNewProviderConfirmationDialogFragment(
serviceInfo.packageName, appName, /* setActivityResult= */ true);
if (fragment == null || mFragmentManager == null) {
return;
}
@@ -482,20 +482,17 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl
boolean isChecked = pref.isChecked();
if (isChecked) {
// Show the error if too many enabled.
if (!togglePackageNameEnabled(packageName)) {
final DialogFragment fragment = newErrorDialogFragment();
if (fragment == null || mFragmentManager == null) {
return true;
}
fragment.show(mFragmentManager, ErrorDialogFragment.TAG);
// The user set the check to true so we need to set it back.
pref.setChecked(false);
// Since we are enabling it we should confirm the user decision with a
// dialog box.
NewProviderConfirmationDialogFragment fragment =
newNewProviderConfirmationDialogFragment(
packageName, title, /* setActivityResult= */ false);
if (fragment == null || mFragmentManager == null) {
return true;
}
fragment.show(mFragmentManager, NewProviderConfirmationDialogFragment.TAG);
return true;
} else {
// If we are disabling the last enabled provider then show a warning.
@@ -546,12 +543,15 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl
/** Create the new provider confirmation dialog. */
private @Nullable NewProviderConfirmationDialogFragment
newNewProviderConfirmationDialogFragment(
@NonNull String packageName, @NonNull CharSequence appName) {
@NonNull String packageName,
@NonNull CharSequence appName,
boolean setActivityResult) {
DialogHost host =
new DialogHost() {
@Override
public void onDialogClick(int whichButton) {
completeEnableProviderDialogBox(whichButton, packageName);
completeEnableProviderDialogBox(
whichButton, packageName, setActivityResult);
}
};
@@ -559,17 +559,19 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl
}
@VisibleForTesting
void completeEnableProviderDialogBox(int whichButton, String packageName) {
void completeEnableProviderDialogBox(
int whichButton, String packageName, boolean setActivityResult) {
int activityResult = -1;
if (whichButton == DialogInterface.BUTTON_POSITIVE) {
if (togglePackageNameEnabled(packageName)) {
// Enable all prefs.
if (mPrefs.containsKey(packageName)) {
mPrefs.get(packageName).setChecked(true);
}
setActivityResult(Activity.RESULT_OK);
activityResult = Activity.RESULT_OK;
} else {
// There are too many providers so set the result as cancelled.
setActivityResult(Activity.RESULT_CANCELED);
activityResult = Activity.RESULT_CANCELED;
// Show the error if too many enabled.
final DialogFragment fragment = newErrorDialogFragment();
@@ -582,7 +584,13 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl
}
} else {
// The user clicked the cancel button so send that result back.
setActivityResult(Activity.RESULT_CANCELED);
activityResult = Activity.RESULT_CANCELED;
}
// If the dialog is being shown because of the intent we should
// return a result.
if (activityResult == -1 || !setActivityResult) {
setActivityResult(activityResult);
}
}
@@ -735,16 +743,17 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl
public Dialog onCreateDialog(Bundle savedInstanceState) {
final Bundle bundle = getArguments();
final Context context = getContext();
final CharSequence appName =
bundle.getCharSequence(CredentialManagerDialogFragment.APP_NAME_KEY);
final String title =
context.getString(
R.string.credman_enable_confirmation_message_title,
bundle.getCharSequence(CredentialManagerDialogFragment.APP_NAME_KEY));
context.getString(R.string.credman_enable_confirmation_message_title, appName);
final String message =
context.getString(R.string.credman_enable_confirmation_message, appName);
return new AlertDialog.Builder(getActivity())
.setTitle(title)
.setMessage(context.getString(R.string.credman_enable_confirmation_message))
.setPositiveButton(
R.string.credman_enable_confirmation_message_positive_button, this)
.setMessage(message)
.setPositiveButton(android.R.string.ok, this)
.setNegativeButton(android.R.string.cancel, this)
.create();
}

View File

@@ -237,20 +237,7 @@ public class BiometricEnrollActivity extends InstrumentedActivity {
}
}
}
if (mHasFeatureFingerprint) {
final FingerprintManager fpManager = getSystemService(FingerprintManager.class);
final List<FingerprintSensorPropertiesInternal> fpProperties =
fpManager.getSensorPropertiesInternal();
final int maxFingerprintsEnrollableIfSUW = getApplicationContext().getResources()
.getInteger(R.integer.suw_max_fingerprints_enrollable);
if (!fpProperties.isEmpty()) {
final int maxEnrolls =
isSetupWizard ? maxFingerprintsEnrollableIfSUW
: fpProperties.get(0).maxEnrollmentsPerUser;
mIsFingerprintEnrollable =
fpManager.getEnrolledFingerprints(mUserId).size() < maxEnrolls;
}
}
updateFingerprintEnrollable(isSetupWizard);
// TODO(b/195128094): remove this restriction
// Consent can only be recorded when this activity is launched directly from the kids
@@ -289,6 +276,23 @@ public class BiometricEnrollActivity extends InstrumentedActivity {
}
}
private void updateFingerprintEnrollable(boolean isSetupWizard) {
if (mHasFeatureFingerprint) {
final FingerprintManager fpManager = getSystemService(FingerprintManager.class);
final List<FingerprintSensorPropertiesInternal> fpProperties =
fpManager.getSensorPropertiesInternal();
final int maxFingerprintsEnrollableIfSUW = getApplicationContext().getResources()
.getInteger(R.integer.suw_max_fingerprints_enrollable);
if (!fpProperties.isEmpty()) {
final int maxEnrolls =
isSetupWizard ? maxFingerprintsEnrollableIfSUW
: fpProperties.get(0).maxEnrollmentsPerUser;
mIsFingerprintEnrollable =
fpManager.getEnrolledFingerprints(mUserId).size() < maxEnrolls;
}
}
}
private void startEnrollWith(@Authenticators.Types int authenticators, boolean setupWizard) {
// If the caller is not setup wizard, and the user has something enrolled, finish.
// Allow parental consent flow to skip this check, since one modality could be consented
@@ -464,12 +468,12 @@ public class BiometricEnrollActivity extends InstrumentedActivity {
mConfirmingCredentials = false;
final boolean isOk =
isSuccessfulConfirmOrChooseCredential(requestCode, resultCode);
if (isOk && (mHasFeatureFace || mHasFeatureFingerprint)) {
if (isOk && (mIsFaceEnrollable || mIsFingerprintEnrollable)) {
// Apply forward animation during the transition from ChooseLock/ConfirmLock to
// SetupFingerprintEnrollIntroduction/FingerprintEnrollmentActivity
TransitionHelper.applyForwardTransition(this, TRANSITION_FADE_THROUGH);
updateGatekeeperPasswordHandle(data);
if (mHasFeatureFingerprint) {
if (mIsFingerprintEnrollable) {
launchFingerprintOnlyEnroll();
} else {
launchFaceOnlyEnroll();
@@ -482,8 +486,15 @@ public class BiometricEnrollActivity extends InstrumentedActivity {
break;
case REQUEST_SINGLE_ENROLL_FINGERPRINT:
mIsSingleEnrolling = false;
if (resultCode == BiometricEnrollBase.RESULT_FINISHED) {
// FingerprintEnrollIntroduction's visibility is determined by
// mIsFingerprintEnrollable. Keep this value up-to-date after a successful
// enrollment.
updateFingerprintEnrollable(WizardManagerHelper.isAnySetupWizard(getIntent()));
}
if ((resultCode == BiometricEnrollBase.RESULT_SKIP
|| resultCode == BiometricEnrollBase.RESULT_FINISHED) && mHasFeatureFace) {
|| resultCode == BiometricEnrollBase.RESULT_FINISHED)
&& mIsFaceEnrollable) {
// Apply forward animation during the transition from
// SetupFingerprintEnroll*/FingerprintEnrollmentActivity to
// SetupFaceEnrollIntroduction
@@ -495,7 +506,7 @@ public class BiometricEnrollActivity extends InstrumentedActivity {
break;
case REQUEST_SINGLE_ENROLL_FACE:
mIsSingleEnrolling = false;
if (resultCode == Activity.RESULT_CANCELED && mHasFeatureFingerprint) {
if (resultCode == Activity.RESULT_CANCELED && mIsFingerprintEnrollable) {
launchFingerprintOnlyEnroll();
} else {
finishOrLaunchHandToParent(resultCode);

View File

@@ -18,6 +18,7 @@ package com.android.settings.biometrics.face;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.hardware.biometrics.SensorProperties;
import android.hardware.face.FaceManager;
import android.hardware.face.FaceSensorPropertiesInternal;
@@ -49,32 +50,17 @@ public class FaceSettingsFooterPreferenceController extends BasePreferenceContro
public FaceSettingsFooterPreferenceController(Context context, String preferenceKey) {
super(context, preferenceKey);
mProvider = FeatureFactory.getFactory(context).getFaceFeatureProvider();
FaceManager faceManager = context.getSystemService(FaceManager.class);
faceManager.addAuthenticatorsRegisteredCallback(
new IFaceAuthenticatorsRegisteredCallback.Stub() {
@Override
public void onAllAuthenticatorsRegistered(
@NonNull List<FaceSensorPropertiesInternal> sensors) {
if (sensors.isEmpty()) {
Log.e(TAG, "No sensors");
return;
}
boolean isFaceStrong = sensors.get(0).sensorStrength
== SensorProperties.STRENGTH_STRONG;
if (mIsFaceStrong == isFaceStrong) {
return;
}
mIsFaceStrong = isFaceStrong;
updateState(mPreference);
}
});
}
@Override
public void displayPreference(PreferenceScreen screen) {
super.displayPreference(screen);
mPreference = screen.findPreference(mPreferenceKey);
if (screen.getContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_FACE)) {
addAuthenticatorsRegisteredCallback(screen.getContext());
} else {
Log.w(TAG, "Not support FEATURE_FACE");
}
}
@Override
@@ -105,4 +91,27 @@ public class FaceSettingsFooterPreferenceController extends BasePreferenceContro
preference.setTitle(AnnotationSpan.linkify(
mContext.getText(footerRes), linkInfo));
}
private void addAuthenticatorsRegisteredCallback(Context context) {
final FaceManager faceManager = context.getSystemService(FaceManager.class);
faceManager.addAuthenticatorsRegisteredCallback(
new IFaceAuthenticatorsRegisteredCallback.Stub() {
@Override
public void onAllAuthenticatorsRegistered(
@NonNull List<FaceSensorPropertiesInternal> sensors) {
if (sensors.isEmpty()) {
Log.e(TAG, "No sensors");
return;
}
boolean isFaceStrong = sensors.get(0).sensorStrength
== SensorProperties.STRENGTH_STRONG;
if (mIsFaceStrong == isFaceStrong) {
return;
}
mIsFaceStrong = isFaceStrong;
updateState(mPreference);
}
});
}
}

View File

@@ -48,6 +48,8 @@ import android.os.UserHandle;
import android.os.UserManager;
import android.os.storage.StorageManager;
import android.service.persistentdata.PersistentDataBlockManager;
import android.text.BidiFormatter;
import android.text.SpannableStringBuilder;
import android.text.TextUtils;
import android.util.EventLog;
import android.util.Log;
@@ -56,6 +58,7 @@ import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.StringRes;
import androidx.annotation.VisibleForTesting;
import androidx.appcompat.app.AlertDialog;
@@ -76,6 +79,7 @@ import com.android.settings.biometrics.BiometricEnrollActivity;
import com.android.settings.biometrics.BiometricEnrollBase;
import com.android.settings.core.SubSettingLauncher;
import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
import com.android.settings.overlay.FeatureFactory;
import com.android.settings.safetycenter.LockScreenSafetySource;
import com.android.settings.search.SearchFeatureProvider;
import com.android.settingslib.RestrictedPreference;
@@ -139,6 +143,9 @@ public class ChooseLockGeneric extends SettingsActivity {
*/
public static final String EXTRA_CHOOSE_LOCK_GENERIC_EXTRAS = "choose_lock_generic_extras";
/** The character ' • ' to separate the setup choose options */
public static final String SEPARATOR = " \u2022 ";
@VisibleForTesting
static final int CONFIRM_EXISTING_REQUEST = 100;
@VisibleForTesting
@@ -628,10 +635,11 @@ public class ChooseLockGeneric extends SettingsActivity {
R.string.face_unlock_set_unlock_password);
} else if (mForBiometrics) {
setPreferenceTitle(ScreenLockType.PATTERN,
R.string.biometrics_unlock_set_unlock_pattern);
setPreferenceTitle(ScreenLockType.PIN, R.string.biometrics_unlock_set_unlock_pin);
getBiometricsPreferenceTitle(ScreenLockType.PATTERN));
setPreferenceTitle(ScreenLockType.PIN,
getBiometricsPreferenceTitle(ScreenLockType.PIN));
setPreferenceTitle(ScreenLockType.PASSWORD,
R.string.biometrics_unlock_set_unlock_password);
getBiometricsPreferenceTitle(ScreenLockType.PASSWORD));
}
if (mManagedPasswordProvider.isSettingManagedPasswordSupported()) {
@@ -652,6 +660,36 @@ public class ChooseLockGeneric extends SettingsActivity {
}
}
@VisibleForTesting
String getBiometricsPreferenceTitle(@NonNull ScreenLockType secureType) {
SpannableStringBuilder ssb = new SpannableStringBuilder();
BidiFormatter bidi = BidiFormatter.getInstance();
// Assume the flow is "Screen Lock" + "Face" + "Fingerprint"
if (mController != null) {
ssb.append(bidi.unicodeWrap(mController.getTitle(secureType)));
} else {
Log.e(TAG, "ChooseLockGenericController is null!");
}
if (mFaceManager != null && mFaceManager.isHardwareDetected() && isFaceSupported()) {
ssb.append(bidi.unicodeWrap(SEPARATOR));
ssb.append(bidi.unicodeWrap(
getResources().getString(R.string.keywords_face_settings)));
}
if (mFingerprintManager != null && mFingerprintManager.isHardwareDetected()) {
ssb.append(bidi.unicodeWrap(SEPARATOR));
ssb.append(bidi.unicodeWrap(
getResources().getString(R.string.security_settings_fingerprint)));
}
return ssb.toString();
}
private boolean isFaceSupported() {
return FeatureFactory.getFactory(getContext().getApplicationContext())
.getFaceFeatureProvider()
.isSetupWizardSupported(getContext().getApplicationContext());
}
private void setPreferenceTitle(ScreenLockType lock, @StringRes int title) {
Preference preference = findPreference(lock.preferenceKey);
if (preference != null) {
@@ -815,6 +853,14 @@ public class ChooseLockGeneric extends SettingsActivity {
return intent;
}
@Override
public void onStop() {
super.onStop();
if (!getActivity().isChangingConfigurations() && !mWaitingForConfirmation) {
getActivity().finish();
}
}
@Override
public void onDestroy() {
super.onDestroy();

View File

@@ -19,6 +19,7 @@ package com.android.settings.privacy;
import static android.safetylabel.SafetyLabelConstants.SAFETY_LABEL_CHANGE_NOTIFICATIONS_ENABLED;
import android.content.Context;
import android.content.pm.PackageManager;
import android.provider.DeviceConfig;
import com.android.settings.core.BasePreferenceController;
@@ -28,7 +29,6 @@ import com.android.settings.core.BasePreferenceController;
* TODO b/264939792: Add tests
*/
public class AppDataSharingUpdatesPreferenceController extends BasePreferenceController {
public AppDataSharingUpdatesPreferenceController(Context context,
String preferenceKey) {
super(context, preferenceKey);
@@ -36,8 +36,16 @@ public class AppDataSharingUpdatesPreferenceController extends BasePreferenceCon
@Override
public int getAvailabilityStatus() {
return DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_PRIVACY,
SAFETY_LABEL_CHANGE_NOTIFICATIONS_ENABLED, false)
return isPrivacySafetyLabelChangeNotificationsEnabled(mContext)
? AVAILABLE : UNSUPPORTED_ON_DEVICE;
}
private boolean isPrivacySafetyLabelChangeNotificationsEnabled(Context context) {
PackageManager packageManager = context.getPackageManager();
return DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_PRIVACY,
SAFETY_LABEL_CHANGE_NOTIFICATIONS_ENABLED, false)
&& !packageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)
&& !packageManager.hasSystemFeature(PackageManager.FEATURE_LEANBACK)
&& !packageManager.hasSystemFeature(PackageManager.FEATURE_WATCH);
}
}

View File

@@ -18,10 +18,14 @@ package com.android.settings.biometrics.face;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
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.Context;
import android.content.pm.PackageManager;
import android.hardware.face.FaceManager;
import android.hardware.face.FaceSensorProperties;
import android.hardware.face.FaceSensorPropertiesInternal;
@@ -59,6 +63,8 @@ public class FaceSettingsFooterPreferenceControllerTest {
private static final String PREF_KEY = "security_face_footer";
@Mock
private FaceManager mFaceManager;
@Mock
PackageManager mPackageManager;
@Captor
private ArgumentCaptor<IFaceAuthenticatorsRegisteredCallback> mCaptor;
private Preference mPreference;
@@ -71,8 +77,20 @@ public class FaceSettingsFooterPreferenceControllerTest {
if (Looper.myLooper() == null) {
Looper.prepare(); // needed to create the preference screen
}
ShadowApplication.getInstance().setSystemService(Context.FACE_SERVICE, mFaceManager);
when(mContext.getPackageManager()).thenReturn(mPackageManager);
when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)).thenReturn(true);
}
private void setupHasFaceFeature() {
when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FACE)).thenReturn(true);
}
private void setupNoFaceFeature() {
when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FACE)).thenReturn(false);
}
private void displayFaceSettingsFooterPreferenceController() {
ShadowApplication.getInstance().setSystemService(Context.FACE_SERVICE, mFaceManager);
mController = new FaceSettingsFooterPreferenceController(mContext, PREF_KEY);
PreferenceScreen screen = new PreferenceManager(mContext).createPreferenceScreen(mContext);
mPreference = new FooterPreference(mContext);
@@ -82,13 +100,24 @@ public class FaceSettingsFooterPreferenceControllerTest {
mController.displayPreference(screen);
}
private void createFaceSettingsFooterPreferenceController() {
ShadowApplication.getInstance().setSystemService(Context.FACE_SERVICE, mFaceManager);
mController = new FaceSettingsFooterPreferenceController(mContext, PREF_KEY);
}
@Test
public void isSliceable_returnFalse() {
setupHasFaceFeature();
displayFaceSettingsFooterPreferenceController();
assertThat(mController.isSliceable()).isFalse();
}
@Test
public void testString_faceNotClass3() throws RemoteException {
setupHasFaceFeature();
displayFaceSettingsFooterPreferenceController();
verify(mFaceManager).addAuthenticatorsRegisteredCallback(mCaptor.capture());
mController.updateState(mPreference);
@@ -112,6 +141,9 @@ public class FaceSettingsFooterPreferenceControllerTest {
@Test
public void testString_faceClass3() throws RemoteException {
setupHasFaceFeature();
displayFaceSettingsFooterPreferenceController();
verify(mFaceManager).addAuthenticatorsRegisteredCallback(mCaptor.capture());
mController.updateState(mPreference);
@@ -132,4 +164,30 @@ public class FaceSettingsFooterPreferenceControllerTest {
assertThat(mPreference.getTitle().toString()).isEqualTo(
mContext.getString(R.string.security_settings_face_settings_footer_class3));
}
@Test
public void testSupportFaceFeature_shouldAddAuthenticatorsRegisteredCallback() {
setupHasFaceFeature();
displayFaceSettingsFooterPreferenceController();
verify(mFaceManager).addAuthenticatorsRegisteredCallback(any());
}
@Test
public void testNoFaceFeature_shouldNotAddAuthenticatorsRegisteredCallback() {
setupNoFaceFeature();
displayFaceSettingsFooterPreferenceController();
verify(mContext, never()).getSystemService(FaceManager.class);
verify(mFaceManager, never()).addAuthenticatorsRegisteredCallback(any());
}
@Test
public void testHasFaceFeature_shouldNotAddAuthenticatorsRegisteredCallback_inCtor() {
setupHasFaceFeature();
createFaceSettingsFooterPreferenceController();
verify(mContext, never()).getSystemService(FaceManager.class);
verify(mFaceManager, never()).addAuthenticatorsRegisteredCallback(any());
}
}

View File

@@ -29,11 +29,14 @@ import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_NONE;
import static com.android.settings.password.ChooseLockGeneric.ChooseLockGenericFragment.KEY_LOCK_SETTINGS_FOOTER;
import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_CALLER_APP_NAME;
import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_DEVICE_PASSWORD_REQUIREMENT_ONLY;
import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_FOR_BIOMETRICS;
import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_IS_CALLING_APP_ADMIN;
import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_REQUESTED_MIN_COMPLEXITY;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.when;
import static org.robolectric.RuntimeEnvironment.application;
import static org.robolectric.Shadows.shadowOf;
@@ -43,6 +46,8 @@ import android.app.admin.PasswordMetrics;
import android.app.admin.PasswordPolicy;
import android.content.Context;
import android.content.Intent;
import android.hardware.face.FaceManager;
import android.hardware.fingerprint.FingerprintManager;
import android.os.Bundle;
import android.provider.Settings.Global;
@@ -55,6 +60,7 @@ import com.android.settings.R;
import com.android.settings.biometrics.BiometricEnrollBase;
import com.android.settings.password.ChooseLockGeneric.ChooseLockGenericFragment;
import com.android.settings.search.SearchFeatureProvider;
import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settings.testutils.shadow.ShadowInteractionJankMonitor;
import com.android.settings.testutils.shadow.ShadowLockPatternUtils;
import com.android.settings.testutils.shadow.ShadowStorageManager;
@@ -65,8 +71,12 @@ import com.android.settingslib.widget.FooterPreference;
import org.junit.After;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
import org.robolectric.Robolectric;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
@@ -86,13 +96,33 @@ import org.robolectric.shadows.ShadowPersistentDataBlockManager;
@Ignore("b/179136903: Tests failed with collapsing toolbar, plan to figure out root cause later.")
public class ChooseLockGenericTest {
@Rule
public final MockitoRule mMockitoRule = MockitoJUnit.rule();
private FakeFeatureFactory mFakeFeatureFactory;
private ChooseLockGenericFragment mFragment;
private ChooseLockGeneric mActivity;
@Mock
private FingerprintManager mFingerprintManager;
@Mock
private FaceManager mFaceManager;
@Before
public void setUp() {
mFakeFeatureFactory = FakeFeatureFactory.setupForTest();
mActivity = Robolectric.buildActivity(ChooseLockGeneric.class)
.create()
.start()
.postCreate(null)
.resume()
.get();
Global.putInt(application.getContentResolver(), Global.DEVICE_PROVISIONED, 1);
mFragment = new ChooseLockGenericFragment();
when(mFaceManager.isHardwareDetected()).thenReturn(true);
when(mFingerprintManager.isHardwareDetected()).thenReturn(true);
when(mFakeFeatureFactory.mFaceFeatureProvider.isSetupWizardSupported(any())).thenReturn(
false);
}
@After
@@ -490,13 +520,47 @@ public class ChooseLockGenericTest {
new PasswordMetrics(CREDENTIAL_TYPE_NONE));
}
@Test
public void updatePreferenceText_supportBiometrics_showFaceAndFingerprint() {
ShadowLockPatternUtils.setRequiredPasswordComplexity(PASSWORD_COMPLEXITY_LOW);
final PasswordPolicy policy = new PasswordPolicy();
policy.quality = PASSWORD_QUALITY_ALPHABETIC;
ShadowLockPatternUtils.setRequestedProfilePasswordMetrics(policy.getMinMetrics());
final Intent intent = new Intent().putExtra(EXTRA_KEY_FOR_BIOMETRICS, true);
initActivity(intent);
final Intent passwordIntent = mFragment.getLockPatternIntent();
assertThat(passwordIntent.getIntExtra(ChooseLockPassword.EXTRA_KEY_MIN_COMPLEXITY,
PASSWORD_COMPLEXITY_NONE)).isEqualTo(PASSWORD_COMPLEXITY_LOW);
final String supportFingerprint = mActivity.getResources().getString(
R.string.security_settings_fingerprint);
final String supportFace = mActivity.getResources().getString(
R.string.keywords_face_settings);
assertThat(mFragment.getBiometricsPreferenceTitle(ScreenLockType.PIN)).contains(
supportFingerprint);
assertThat(mFragment.getBiometricsPreferenceTitle(ScreenLockType.PIN)).contains(
supportFace);
assertThat(mFragment.getBiometricsPreferenceTitle(ScreenLockType.PATTERN)).contains(
supportFingerprint);
assertThat(mFragment.getBiometricsPreferenceTitle(ScreenLockType.PATTERN)).contains(
supportFace);
assertThat(mFragment.getBiometricsPreferenceTitle(ScreenLockType.PASSWORD)).contains(
supportFingerprint);
assertThat(mFragment.getBiometricsPreferenceTitle(ScreenLockType.PASSWORD)).contains(
supportFace);
}
private void initActivity(@Nullable Intent intent) {
if (intent == null) {
intent = new Intent();
}
intent.putExtra(ChooseLockGeneric.CONFIRM_CREDENTIALS, false);
// TODO(b/275023433) This presents the activity from being made 'visible` is workaround
mActivity = Robolectric.buildActivity(ChooseLockGeneric.InternalActivity.class, intent)
.setup().get();
.create().start().postCreate(null).resume().get();
mActivity.getSupportFragmentManager().beginTransaction().add(mFragment, null).commitNow();
}
}

View File

@@ -23,13 +23,22 @@ import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_R
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.when;
import static org.robolectric.RuntimeEnvironment.application;
import android.content.Intent;
import android.hardware.face.FaceManager;
import android.hardware.fingerprint.FingerprintManager;
import android.provider.Settings;
import android.text.TextUtils;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import com.android.settings.R;
import com.android.settings.password.SetupChooseLockGeneric.SetupChooseLockGenericFragment;
import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settings.testutils.shadow.ShadowLockPatternUtils;
import com.android.settings.testutils.shadow.ShadowPasswordUtils;
import com.android.settings.testutils.shadow.ShadowUserManager;
@@ -38,8 +47,13 @@ import com.android.settings.testutils.shadow.ShadowUtils;
import com.google.android.setupdesign.GlifPreferenceLayout;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
import org.robolectric.Robolectric;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.Shadows;
@@ -56,6 +70,28 @@ import java.util.List;
})
public class SetupChooseLockGenericTest {
@Rule
public final MockitoRule mMockitoRule = MockitoJUnit.rule();
@Mock
private FakeFeatureFactory mFakeFeatureFactory;
@Mock
private FingerprintManager mFingerprintManager;
@Mock
private FaceManager mFaceManager;
@Before
public void setUp() {
ShadowUtils.setFingerprintManager(mFingerprintManager);
ShadowUtils.setFaceManager(mFaceManager);
mFakeFeatureFactory = FakeFeatureFactory.setupForTest();
Settings.Global.putInt(application.getContentResolver(), Settings.Global.DEVICE_PROVISIONED,
0);
when(mFaceManager.isHardwareDetected()).thenReturn(true);
when(mFingerprintManager.isHardwareDetected()).thenReturn(true);
}
@After
public void tearDown() {
ShadowPasswordUtils.reset();
@@ -102,13 +138,91 @@ public class SetupChooseLockGenericTest {
assertThat(view.getDescriptionText().toString()).isEqualTo(fragment.loadDescriptionText());
}
@Test
public void updatePreferenceTextShowScreenLockAndFingerprint() {
when(mFakeFeatureFactory.mFaceFeatureProvider.isSetupWizardSupported(any())).thenReturn(
false);
SetupChooseLockGenericFragment fragment = getFragmentOfSetupChooseLockGeneric(true);
final String supportFingerprint = fragment.getResources().getString(
R.string.security_settings_fingerprint);
final String supportFace = fragment.getResources().getString(
R.string.keywords_face_settings);
assertThat(fragment.getBiometricsPreferenceTitle(ScreenLockType.PIN)).contains(
supportFingerprint);
assertThat(fragment.getBiometricsPreferenceTitle(ScreenLockType.PIN)).doesNotContain(
supportFace);
assertThat(fragment.getBiometricsPreferenceTitle(ScreenLockType.PATTERN)).contains(
supportFingerprint);
assertThat(fragment.getBiometricsPreferenceTitle(ScreenLockType.PATTERN)).doesNotContain(
supportFace);
assertThat(fragment.getBiometricsPreferenceTitle(ScreenLockType.PASSWORD)).contains(
supportFingerprint);
assertThat(fragment.getBiometricsPreferenceTitle(ScreenLockType.PASSWORD)).doesNotContain(
supportFace);
}
@Test
public void updatePreferenceTextShowScreenLockAndShowFaceAndShowFingerprint() {
when(mFakeFeatureFactory.mFaceFeatureProvider.isSetupWizardSupported(any())).thenReturn(
true);
SetupChooseLockGenericFragment fragment = getFragmentOfSetupChooseLockGeneric(true);
final String supportFingerprint = fragment.getResources().getString(
R.string.security_settings_fingerprint);
final String supportFace = fragment.getResources().getString(
R.string.keywords_face_settings);
assertThat(fragment.getBiometricsPreferenceTitle(ScreenLockType.PIN)).contains(
supportFingerprint);
assertThat(fragment.getBiometricsPreferenceTitle(ScreenLockType.PIN)).contains(
supportFace);
assertThat(fragment.getBiometricsPreferenceTitle(ScreenLockType.PATTERN)).contains(
supportFingerprint);
assertThat(fragment.getBiometricsPreferenceTitle(ScreenLockType.PATTERN)).contains(
supportFace);
assertThat(fragment.getBiometricsPreferenceTitle(ScreenLockType.PASSWORD)).contains(
supportFingerprint);
assertThat(fragment.getBiometricsPreferenceTitle(ScreenLockType.PASSWORD)).contains(
supportFace);
}
@Test
public void updatePreferenceTextShowScreenLockAndShowFingerprint() {
when(mFakeFeatureFactory.mFaceFeatureProvider.isSetupWizardSupported(any())).thenReturn(
false);
SetupChooseLockGenericFragment fragment = getFragmentOfSetupChooseLockGeneric(true);
final String supportFingerprint = fragment.getResources().getString(
R.string.security_settings_fingerprint);
final String supportFace = fragment.getResources().getString(
R.string.keywords_face_settings);
assertThat(fragment.getBiometricsPreferenceTitle(ScreenLockType.PIN)).contains(
supportFingerprint);
assertThat(fragment.getBiometricsPreferenceTitle(ScreenLockType.PIN)).doesNotContain(
supportFace);
assertThat(fragment.getBiometricsPreferenceTitle(ScreenLockType.PATTERN)).contains(
supportFingerprint);
assertThat(fragment.getBiometricsPreferenceTitle(ScreenLockType.PATTERN)).doesNotContain(
supportFace);
assertThat(fragment.getBiometricsPreferenceTitle(ScreenLockType.PASSWORD)).contains(
supportFingerprint);
assertThat(fragment.getBiometricsPreferenceTitle(ScreenLockType.PASSWORD)).doesNotContain(
supportFace);
}
private SetupChooseLockGenericFragment getFragmentOfSetupChooseLockGeneric(boolean biometric) {
ShadowPasswordUtils.addGrantedPermission(REQUEST_PASSWORD_COMPLEXITY);
Intent intent = new Intent("com.android.settings.SETUP_LOCK_SCREEN");
intent.putExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY, PASSWORD_COMPLEXITY_HIGH);
intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT, biometric);
intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FACE, biometric);
// TODO(b/275023433) This presents the activity from being made 'visible` is workaround
SetupChooseLockGeneric activity =
Robolectric.buildActivity(SetupChooseLockGeneric.class, intent).setup().get();
Robolectric.buildActivity(SetupChooseLockGeneric.class,
intent).create().start().postCreate(null).resume().get();
List<Fragment> fragments = activity.getSupportFragmentManager().getFragments();
assertThat(fragments).isNotNull();

View File

@@ -0,0 +1,116 @@
/*
* Copyright (C) 2023 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.privacy;
import static android.content.pm.PackageManager.FEATURE_AUTOMOTIVE;
import static android.content.pm.PackageManager.FEATURE_LEANBACK;
import static android.content.pm.PackageManager.FEATURE_WATCH;
import static com.android.settings.core.BasePreferenceController.AVAILABLE;
import static com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_DEVICE;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doReturn;
import android.content.Context;
import android.content.pm.PackageManager;
import android.provider.DeviceConfig;
import android.provider.Settings;
import android.safetylabel.SafetyLabelConstants;
import com.android.settings.testutils.shadow.ShadowDeviceConfig;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoSession;
import org.mockito.quality.Strictness;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
import java.util.Arrays;
import java.util.List;
@RunWith(RobolectricTestRunner.class)
@Config(shadows = {ShadowDeviceConfig.class})
public class AppDataSharingUpdatesPreferenceControllerTest {
public static final String PREFERENCE_KEY = "PREFERENCE_KEY";
private static final List<String> sUnsupportedFormFactors =
Arrays.asList(FEATURE_AUTOMOTIVE, FEATURE_LEANBACK, FEATURE_WATCH);
private MockitoSession mMockitoSession;
@Mock
private PackageManager mPackageManager;
@Mock
private Context mContext;
private AppDataSharingUpdatesPreferenceController mController;
@Before
public void setUp() {
mMockitoSession = Mockito.mockitoSession()
.initMocks(this)
.strictness(Strictness.WARN)
.startMocking();
doReturn(mPackageManager).when(mContext).getPackageManager();
mController = new AppDataSharingUpdatesPreferenceController(mContext, PREFERENCE_KEY);
for (String formFactor : sUnsupportedFormFactors) {
doReturn(false).when(mPackageManager).hasSystemFeature(eq(formFactor));
}
}
@After
public void tearDown() {
mMockitoSession.finishMocking();
}
@Test
public void whenSafetyLabelsDisabled_thenPreferenceUnavailable()
throws Exception {
setSafetyLabelsDeviceConfigEnabled(false);
assertThat(mController.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE);
}
@Test
public void whenSafetyLabelsEnabled_andSupportedFormFactor_thenPreferenceAvailable()
throws Exception {
setSafetyLabelsDeviceConfigEnabled(true);
assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
}
@Test
public void whenSafetyLabelsEnabled_andUnsupportedFormFactor_thenPreferenceUnavailable()
throws Exception {
setSafetyLabelsDeviceConfigEnabled(true);
for (String formFactor : sUnsupportedFormFactors) {
doReturn(true).when(mPackageManager).hasSystemFeature(eq(formFactor));
assertThat(mController.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE);
doReturn(false).when(mPackageManager).hasSystemFeature(eq(formFactor));
}
}
private void setSafetyLabelsDeviceConfigEnabled(boolean newValue)
throws Settings.SettingNotFoundException {
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_PRIVACY,
SafetyLabelConstants.SAFETY_LABEL_CHANGE_NOTIFICATIONS_ENABLED,
((Boolean) newValue).toString(), /* makeDefault */ false);
}
}

View File

@@ -389,7 +389,7 @@ public class CredentialManagerPreferenceControllerTest {
Intent intent = new Intent(PRIMARY_INTENT);
intent.setData(Uri.parse("package:" + packageName));
assertThat(controller.verifyReceivedIntent(intent)).isTrue();
controller.completeEnableProviderDialogBox(DialogInterface.BUTTON_POSITIVE, packageName);
controller.completeEnableProviderDialogBox(DialogInterface.BUTTON_POSITIVE, packageName, true);
assertThat(mReceivedResultCode.get()).isEqualTo(Activity.RESULT_OK);
}
@@ -404,7 +404,7 @@ public class CredentialManagerPreferenceControllerTest {
Intent intent = new Intent(PRIMARY_INTENT);
intent.setData(Uri.parse("package:" + packageName));
assertThat(controller.verifyReceivedIntent(intent)).isTrue();
controller.completeEnableProviderDialogBox(DialogInterface.BUTTON_NEGATIVE, packageName);
controller.completeEnableProviderDialogBox(DialogInterface.BUTTON_NEGATIVE, packageName, true);
assertThat(mReceivedResultCode.get()).isEqualTo(Activity.RESULT_CANCELED);
}
@@ -430,7 +430,7 @@ public class CredentialManagerPreferenceControllerTest {
Intent intent = new Intent(ALTERNATE_INTENT);
intent.setData(Uri.parse("package:" + packageName));
assertThat(controller.verifyReceivedIntent(intent)).isTrue();
controller.completeEnableProviderDialogBox(DialogInterface.BUTTON_POSITIVE, packageName);
controller.completeEnableProviderDialogBox(DialogInterface.BUTTON_POSITIVE, packageName, true);
assertThat(mReceivedResultCode.get()).isEqualTo(Activity.RESULT_OK);
}
@@ -445,7 +445,7 @@ public class CredentialManagerPreferenceControllerTest {
Intent intent = new Intent(ALTERNATE_INTENT);
intent.setData(Uri.parse("package:" + packageName));
assertThat(controller.verifyReceivedIntent(intent)).isTrue();
controller.completeEnableProviderDialogBox(DialogInterface.BUTTON_NEGATIVE, packageName);
controller.completeEnableProviderDialogBox(DialogInterface.BUTTON_NEGATIVE, packageName, true);
assertThat(mReceivedResultCode.get()).isEqualTo(Activity.RESULT_CANCELED);
}