From dcd6fc593da212d985a37b199700211b29fccbc1 Mon Sep 17 00:00:00 2001 From: Pavel Grafov Date: Fri, 29 May 2020 13:57:24 +0100 Subject: [PATCH 1/4] Launch ForgotPasswordActivity in a new task. This way the notificaiton about locked profile can function as expected. Prior to this change ForgotPasswordActivity was launched in the same task as initial profile credential confirmation. As a result, when ForgotPasswordActivity was in the foreground, the notification tap won't do anything since a task for CONFIRM_DEVICE_CREDENTIAL_WITH_USER was already in the foreground. Bug: 157554361 Test: manual, with TestDPC Change-Id: Ifc9d8e1fb8658c3f22926d7fa35da1e60eadb3db --- .../settings/password/ConfirmDeviceCredentialBaseFragment.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/com/android/settings/password/ConfirmDeviceCredentialBaseFragment.java b/src/com/android/settings/password/ConfirmDeviceCredentialBaseFragment.java index a60fab97a3d..3440071bf40 100644 --- a/src/com/android/settings/password/ConfirmDeviceCredentialBaseFragment.java +++ b/src/com/android/settings/password/ConfirmDeviceCredentialBaseFragment.java @@ -152,6 +152,7 @@ public abstract class ConfirmDeviceCredentialBaseFragment extends InstrumentedFr mForgotButton.setOnClickListener(v -> { final Intent intent = new Intent(); intent.setClassName(SETTINGS_PACKAGE_NAME, ForgotPasswordActivity.class.getName()); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.putExtra(Intent.EXTRA_USER_ID, mUserId); getActivity().startActivity(intent); getActivity().finish(); From d00fd7f36214bb2931fd4bf89fbc034a5626a5e0 Mon Sep 17 00:00:00 2001 From: Joe Bolinger Date: Tue, 23 Nov 2021 00:52:23 +0000 Subject: [PATCH 2/4] Remove face auth from setup wizard when configured as a convenience. Fix: 206867696 Test: manual (enroll via SUW with/without unicorn) Change-Id: I41bf7488cf30ffe3e0d09282e923347c7f5938df --- .../biometrics/BiometricEnrollActivity.java | 53 ++++++++++++------- 1 file changed, 33 insertions(+), 20 deletions(-) diff --git a/src/com/android/settings/biometrics/BiometricEnrollActivity.java b/src/com/android/settings/biometrics/BiometricEnrollActivity.java index 690ef13be7d..c74e85e54c2 100644 --- a/src/com/android/settings/biometrics/BiometricEnrollActivity.java +++ b/src/com/android/settings/biometrics/BiometricEnrollActivity.java @@ -32,6 +32,7 @@ import android.hardware.biometrics.BiometricAuthenticator; import android.hardware.biometrics.BiometricManager; import android.hardware.biometrics.BiometricManager.Authenticators; import android.hardware.biometrics.BiometricManager.BiometricError; +import android.hardware.biometrics.SensorProperties; import android.hardware.face.FaceManager; import android.hardware.face.FaceSensorPropertiesInternal; import android.hardware.fingerprint.FingerprintManager; @@ -175,8 +176,22 @@ public class BiometricEnrollActivity extends InstrumentedActivity { mHasFeatureFingerprint = pm.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT); mHasFeatureFace = pm.hasSystemFeature(PackageManager.FEATURE_FACE); + // Default behavior is to enroll BIOMETRIC_WEAK or above. See ACTION_BIOMETRIC_ENROLL. + final int authenticators = getIntent().getIntExtra( + EXTRA_BIOMETRIC_AUTHENTICATORS_ALLOWED, Authenticators.BIOMETRIC_WEAK); + Log.d(TAG, "Authenticators: " + authenticators); + + mParentalOptionsRequired = intent.getBooleanExtra(EXTRA_REQUIRE_PARENTAL_CONSENT, false); + mSkipReturnToParent = intent.getBooleanExtra(EXTRA_SKIP_RETURN_TO_PARENT, false); + // determine what can be enrolled final boolean isSetupWizard = WizardManagerHelper.isAnySetupWizard(getIntent()); + final boolean isMultiSensor = mHasFeatureFace && mHasFeatureFingerprint; + + Log.d(TAG, "parentalOptionsRequired: " + mParentalOptionsRequired + + ", skipReturnToParent: " + mSkipReturnToParent + + ", isSetupWizard: " + isSetupWizard + + ", isMultiSensor: " + isMultiSensor); if (mHasFeatureFace) { final FaceManager faceManager = getSystemService(FaceManager.class); @@ -185,11 +200,23 @@ public class BiometricEnrollActivity extends InstrumentedActivity { final int maxFacesEnrollableIfSUW = getApplicationContext().getResources() .getInteger(R.integer.suw_max_faces_enrollable); if (!faceProperties.isEmpty()) { + final FaceSensorPropertiesInternal props = faceProperties.get(0); final int maxEnrolls = - isSetupWizard ? maxFacesEnrollableIfSUW - : faceProperties.get(0).maxEnrollmentsPerUser; + isSetupWizard ? maxFacesEnrollableIfSUW : props.maxEnrollmentsPerUser; mIsFaceEnrollable = faceManager.getEnrolledFaces(mUserId).size() < maxEnrolls; + + // exclude face enrollment from setup wizard if configured as a convenience + // isSetupWizard is always false for unicorn enrollment, so if consent is + // required check if setup has completed instead. + final boolean isSettingUp = isSetupWizard || (mParentalOptionsRequired + && !WizardManagerHelper.isUserSetupComplete(this)); + if (isSettingUp && isMultiSensor && mIsFaceEnrollable) { + if (props.sensorStrength == SensorProperties.STRENGTH_CONVENIENCE) { + Log.i(TAG, "Excluding face from SuW enrollment (STRENGTH_CONVENIENCE)"); + mIsFaceEnrollable = false; + } + } } } if (mHasFeatureFingerprint) { @@ -207,13 +234,6 @@ public class BiometricEnrollActivity extends InstrumentedActivity { } } - mParentalOptionsRequired = intent.getBooleanExtra(EXTRA_REQUIRE_PARENTAL_CONSENT, false); - mSkipReturnToParent = intent.getBooleanExtra(EXTRA_SKIP_RETURN_TO_PARENT, false); - - Log.d(TAG, "parentalOptionsRequired: " + mParentalOptionsRequired - + ", skipReturnToParent: " + mSkipReturnToParent - + ", isSetupWizard: " + isSetupWizard); - // TODO(b/195128094): remove this restriction // Consent can only be recorded when this activity is launched directly from the kids // module. This can be removed when there is a way to notify consent status out of band. @@ -247,19 +267,10 @@ public class BiometricEnrollActivity extends InstrumentedActivity { setOrConfirmCredentialsNow(); } else { // Start enrollment process if we haven't bailed out yet - startEnroll(); + startEnrollWith(authenticators, isSetupWizard); } } - private void startEnroll() { - // Default behavior is to enroll BIOMETRIC_WEAK or above. See ACTION_BIOMETRIC_ENROLL. - final int authenticators = getIntent().getIntExtra( - EXTRA_BIOMETRIC_AUTHENTICATORS_ALLOWED, Authenticators.BIOMETRIC_WEAK); - Log.d(TAG, "Authenticators: " + authenticators); - - startEnrollWith(authenticators, WizardManagerHelper.isAnySetupWizard(getIntent())); - } - 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 @@ -339,7 +350,9 @@ public class BiometricEnrollActivity extends InstrumentedActivity { final boolean fpConsentRequired = ParentalControlsUtils .parentConsentRequired(this, BiometricAuthenticator.TYPE_FINGERPRINT) != null; - final boolean requestFaceConsent = faceConsentRequired && mHasFeatureFace; + final boolean requestFaceConsent = faceConsentRequired + && mHasFeatureFace + && mIsFaceEnrollable; final boolean requestFpConsent = fpConsentRequired && mHasFeatureFingerprint; Log.d(TAG, "faceConsentRequired: " + faceConsentRequired From a8c12b429812be513e7d918596d2583f4c5037a1 Mon Sep 17 00:00:00 2001 From: Pavel Grafov Date: Wed, 24 Nov 2021 16:19:44 +0000 Subject: [PATCH 3/4] Check user validity before retrying authentication When managed profile gets wiped Settings may crash with SecurityException when trying to retry authentication for no longer valid user. Test: manually with TestDPC Bug: 201513984 Change-Id: Ib7309abf89be76fcc1bf756c37c09d6b60c6b95c --- .../settings/password/ConfirmDeviceCredentialActivity.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/com/android/settings/password/ConfirmDeviceCredentialActivity.java b/src/com/android/settings/password/ConfirmDeviceCredentialActivity.java index 03e83a4f61b..22d87a51a0e 100644 --- a/src/com/android/settings/password/ConfirmDeviceCredentialActivity.java +++ b/src/com/android/settings/password/ConfirmDeviceCredentialActivity.java @@ -108,6 +108,10 @@ public class ConfirmDeviceCredentialActivity extends FragmentActivity { if (errorCode == BiometricPrompt.BIOMETRIC_ERROR_USER_CANCELED || errorCode == BiometricPrompt.BIOMETRIC_ERROR_CANCELED) { finish(); + } else if (mUserManager.getUserInfo(mUserId) == null) { + // This can happen when profile gets wiped due to too many failed auth attempts. + Log.i(TAG, "Finishing, user no longer valid: " + mUserId); + finish(); } else { // All other errors go to some version of CC showConfirmCredentials(); From 8b1ecea0601cb36c8c510350a1fddcdbeff7876b Mon Sep 17 00:00:00 2001 From: Zoey Chen Date: Thu, 25 Nov 2021 00:02:33 +0800 Subject: [PATCH 4/4] [Settings] Should show carrier network if airplane mode is on https://hsv.googleplex.com/6007361661566976 Test: atest SubscriptionsPreferenceControllerTest Bug: 206990845 Change-Id: Id39b662f33b201a8e4ce53c34c3007eca9a40edf --- .../SubscriptionsPreferenceController.java | 44 ++++++++++-------- ...SubscriptionsPreferenceControllerTest.java | 45 ++++++++++++++++++- 2 files changed, 70 insertions(+), 19 deletions(-) diff --git a/src/com/android/settings/network/SubscriptionsPreferenceController.java b/src/com/android/settings/network/SubscriptionsPreferenceController.java index b8726808b45..9e1b6da24e9 100644 --- a/src/com/android/settings/network/SubscriptionsPreferenceController.java +++ b/src/com/android/settings/network/SubscriptionsPreferenceController.java @@ -94,6 +94,7 @@ public class SubscriptionsPreferenceController extends AbstractPreferenceControl private SignalStrengthListener mSignalStrengthListener; private TelephonyDisplayInfoListener mTelephonyDisplayInfoListener; private WifiPickerTrackerHelper mWifiPickerTrackerHelper; + private final WifiManager mWifiManager; @VisibleForTesting final BroadcastReceiver mConnectionChangeReceiver = new BroadcastReceiver() { @@ -150,6 +151,7 @@ public class SubscriptionsPreferenceController extends AbstractPreferenceControl mStartOrder = startOrder; mTelephonyManager = context.getSystemService(TelephonyManager.class); mSubscriptionManager = context.getSystemService(SubscriptionManager.class); + mWifiManager = context.getSystemService(WifiManager.class); mSubscriptionPreferences = new ArrayMap<>(); mSubscriptionsListener = new SubscriptionsChangeListener(context, this); mDataEnabledListener = new MobileDataEnabledListener(context, this); @@ -271,9 +273,7 @@ public class SubscriptionsPreferenceController extends AbstractPreferenceControl final boolean isDataInService = (regInfo == null) ? false : regInfo.isRegistered(); - final boolean isCarrierNetworkActive = - (mWifiPickerTrackerHelper != null) - && mWifiPickerTrackerHelper.isCarrierNetworkActive(); + final boolean isCarrierNetworkActive = isCarrierNetworkActive(); String result = mSubsPrefCtrlInjector.getNetworkType( mContext, mConfig, mTelephonyDisplayInfo, subId, isCarrierNetworkActive); if (mSubsPrefCtrlInjector.isActiveCellularNetwork(mContext) || isCarrierNetworkActive) { @@ -291,20 +291,15 @@ public class SubscriptionsPreferenceController extends AbstractPreferenceControl final SignalStrength strength = tmForSubId.getSignalStrength(); int level = (strength == null) ? 0 : strength.getLevel(); int numLevels = SignalStrength.NUM_SIGNAL_STRENGTH_BINS; - if (shouldInflateSignalStrength(subId)) { - level += 1; + boolean isCarrierNetworkActive = isCarrierNetworkActive(); + if (shouldInflateSignalStrength(subId) || isCarrierNetworkActive) { + level = isCarrierNetworkActive + ? SignalStrength.NUM_SIGNAL_STRENGTH_BINS + : (level + 1); numLevels += 1; } - Drawable icon = mSubsPrefCtrlInjector.getIcon(mContext, level, numLevels, - !mTelephonyManager.isDataEnabled()); - final boolean isActiveCellularNetwork = - mSubsPrefCtrlInjector.isActiveCellularNetwork(mContext); - if (isActiveCellularNetwork || (mWifiPickerTrackerHelper != null) - && mWifiPickerTrackerHelper.isCarrierNetworkActive()) { - icon.setTint(Utils.getColorAccentDefaultColor(mContext)); - return icon; - } + Drawable icon = mContext.getDrawable(R.drawable.ic_signal_strength_zero_bar_no_internet); final ServiceState serviceState = tmForSubId.getServiceState(); final NetworkRegistrationInfo regInfo = (serviceState == null) @@ -319,11 +314,17 @@ public class SubscriptionsPreferenceController extends AbstractPreferenceControl final boolean isVoiceInService = (serviceState == null) ? false : (serviceState.getState() == ServiceState.STATE_IN_SERVICE); - if (isDataInService || isVoiceInService) { - return icon; + if (isDataInService || isVoiceInService || isCarrierNetworkActive) { + icon = mSubsPrefCtrlInjector.getIcon(mContext, level, numLevels, + !mTelephonyManager.isDataEnabled()); + } + + final boolean isActiveCellularNetwork = + mSubsPrefCtrlInjector.isActiveCellularNetwork(mContext); + if (isActiveCellularNetwork || isCarrierNetworkActive) { + icon.setTint(Utils.getColorAccentDefaultColor(mContext)); } - icon = mContext.getDrawable(R.drawable.ic_signal_strength_zero_bar_no_internet); return icon; } @@ -417,7 +418,8 @@ public class SubscriptionsPreferenceController extends AbstractPreferenceControl */ @Override public boolean isAvailable() { - if (mSubscriptionsListener.isAirplaneModeOn()) { + if (mSubscriptionsListener.isAirplaneModeOn() + && (!mWifiManager.isWifiEnabled() || !isCarrierNetworkActive())) { return false; } List subInfoList = @@ -425,6 +427,7 @@ public class SubscriptionsPreferenceController extends AbstractPreferenceControl if (subInfoList == null) { return false; } + return subInfoList.stream() // Avoid from showing subscription(SIM)s which has been marked as hidden // For example, only one subscription will be shown when there're multiple @@ -495,6 +498,11 @@ public class SubscriptionsPreferenceController extends AbstractPreferenceControl return new SubsPrefCtrlInjector(); } + boolean isCarrierNetworkActive() { + return mWifiPickerTrackerHelper != null + && mWifiPickerTrackerHelper.isCarrierNetworkActive(); + } + /** * To inject necessary data from each static api. */ diff --git a/tests/unit/src/com/android/settings/network/SubscriptionsPreferenceControllerTest.java b/tests/unit/src/com/android/settings/network/SubscriptionsPreferenceControllerTest.java index 8b03352c62b..ac07faefa47 100644 --- a/tests/unit/src/com/android/settings/network/SubscriptionsPreferenceControllerTest.java +++ b/tests/unit/src/com/android/settings/network/SubscriptionsPreferenceControllerTest.java @@ -39,6 +39,7 @@ import android.graphics.drawable.Drawable; import android.net.ConnectivityManager; import android.net.Network; import android.net.NetworkCapabilities; +import android.net.wifi.WifiManager; import android.os.Looper; import android.os.UserManager; import android.provider.Settings; @@ -102,6 +103,8 @@ public class SubscriptionsPreferenceControllerTest { private LifecycleOwner mLifecycleOwner; @Mock private WifiPickerTrackerHelper mWifiPickerTrackerHelper; + @Mock + private WifiManager mWifiManager; private LifecycleRegistry mLifecycleRegistry; private int mOnChildUpdatedCount; @@ -132,6 +135,7 @@ public class SubscriptionsPreferenceControllerTest { when(mConnectivityManager.getNetworkCapabilities(mActiveNetwork)) .thenReturn(mNetworkCapabilities); when(mUserManager.isAdminUser()).thenReturn(true); + when(mContext.getSystemService(WifiManager.class)).thenReturn(mWifiManager); when(mLifecycleOwner.getLifecycle()).thenReturn(mLifecycleRegistry); mPreferenceManager = new PreferenceManager(mContext); @@ -171,16 +175,55 @@ public class SubscriptionsPreferenceControllerTest { } @Test - public void isAvailable_airplaneModeOn_availableFalse() { + public void isAvailable_airplaneModeOnWifiOff_availableFalse() { setupMockSubscriptions(2); assertThat(mController.isAvailable()).isTrue(); + when(mWifiManager.isWifiEnabled()).thenReturn(false); Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 1); assertThat(mController.isAvailable()).isFalse(); } + @Test + public void isAvailable_airplaneModeOnWifiOnWithNoCarrierNetwork_availableFalse() { + setupMockSubscriptions(2); + + assertThat(mController.isAvailable()).isTrue(); + when(mWifiManager.isWifiEnabled()).thenReturn(true); + doReturn(false).when(mWifiPickerTrackerHelper).isCarrierNetworkActive(); + + Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 1); + + assertThat(mController.isAvailable()).isFalse(); + } + + @Test + public void isAvailable_airplaneModeOnWifiOffWithCarrierNetwork_availableTrue() { + setupMockSubscriptions(1); + + when(mWifiManager.isWifiEnabled()).thenReturn(false); + doReturn(true).when(mWifiPickerTrackerHelper).isCarrierNetworkActive(); + + Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 1); + + assertThat(mController.isAvailable()).isFalse(); + } + + @Test + public void isAvailable_airplaneModeOff_availableFalse() { + setupMockSubscriptions(2); + + assertThat(mController.isAvailable()).isTrue(); + when(mWifiManager.isWifiEnabled()).thenReturn(true); + doReturn(true).when(mWifiPickerTrackerHelper).isCarrierNetworkActive(); + + Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 0); + + assertThat(mController.isAvailable()).isTrue(); + } + @Test @UiThreadTest public void displayPreference_providerAndHasSim_showPreference() {