Merge ab/AP4A.240925.013 into aosp-main-future

Bug: 370570306
Merged-In: I4e2a72a80f68579d60466e859370b6fd93a8cd23
Change-Id: Ifc87474ccff4172524295035e70916216b41a715
This commit is contained in:
Xin Li
2024-11-21 15:10:02 -08:00
117 changed files with 3390 additions and 4815 deletions

View File

@@ -1505,17 +1505,18 @@ public final class Utils extends com.android.settingslib.Utils {
* @return biometric status when mandatory biometrics authentication is requested
*/
public static BiometricStatus requestBiometricAuthenticationForMandatoryBiometrics(
@NonNull Context context,
boolean biometricsAuthenticationRequested, int userId) {
@NonNull Context context, boolean biometricsAuthenticationRequested, int userId) {
final BiometricManager biometricManager = context.getSystemService(BiometricManager.class);
if (biometricManager == null) {
Log.e(TAG, "Biometric Manager is null.");
return BiometricStatus.NOT_ACTIVE;
}
final int status = biometricManager.canAuthenticate(userId,
BiometricManager.Authenticators.MANDATORY_BIOMETRICS);
if (android.hardware.biometrics.Flags.mandatoryBiometrics()
&& !biometricsAuthenticationRequested) {
final UserManager userManager = context.getSystemService(
UserManager.class);
final int status = biometricManager.canAuthenticate(getEffectiveUserId(
userManager, userId), BiometricManager.Authenticators.MANDATORY_BIOMETRICS);
switch(status) {
case BiometricManager.BIOMETRIC_SUCCESS:
return BiometricStatus.OK;
@@ -1544,8 +1545,10 @@ public final class Utils extends com.android.settingslib.Utils {
*/
public static void launchBiometricPromptForMandatoryBiometrics(@NonNull Fragment fragment,
int requestCode, int userId, boolean hideBackground) {
final UserManager userManager = (UserManager) fragment.getContext().getSystemService(
UserManager.class);
fragment.startActivityForResult(getIntentForBiometricAuthentication(fragment.getResources(),
userId, hideBackground), requestCode);
getEffectiveUserId(userManager, userId), hideBackground), requestCode);
}
/**
@@ -1561,21 +1564,32 @@ public final class Utils extends com.android.settingslib.Utils {
*/
public static void launchBiometricPromptForMandatoryBiometrics(@NonNull Activity activity,
int requestCode, int userId, boolean hideBackground) {
final UserManager userManager = activity.getSystemService(UserManager.class);
activity.startActivityForResult(getIntentForBiometricAuthentication(
activity.getResources(), userId, hideBackground), requestCode);
activity.getResources(), getEffectiveUserId(userManager, userId),
hideBackground), requestCode);
}
private static Intent getIntentForBiometricAuthentication(Resources resources, int userId,
boolean hideBackground) {
private static int getEffectiveUserId(UserManager userManager, int userId) {
if (userManager != null) {
return userManager.getCredentialOwnerProfile(userId);
}
return userId;
}
private static Intent getIntentForBiometricAuthentication(Resources resources,
int effectiveUserId, boolean hideBackground) {
final Intent intent = new Intent();
intent.putExtra(BIOMETRIC_PROMPT_AUTHENTICATORS,
BiometricManager.Authenticators.MANDATORY_BIOMETRICS);
if (android.hardware.biometrics.Flags.mandatoryBiometrics()) {
intent.putExtra(BIOMETRIC_PROMPT_AUTHENTICATORS,
BiometricManager.Authenticators.MANDATORY_BIOMETRICS);
}
intent.putExtra(BIOMETRIC_PROMPT_NEGATIVE_BUTTON_TEXT,
resources.getString(R.string.cancel));
intent.putExtra(KeyguardManager.EXTRA_DESCRIPTION,
resources.getString(R.string.mandatory_biometrics_prompt_description));
intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_ALLOW_ANY_USER, true);
intent.putExtra(EXTRA_USER_ID, userId);
intent.putExtra(EXTRA_USER_ID, effectiveUserId);
intent.putExtra(BIOMETRIC_PROMPT_HIDE_BACKGROUND, hideBackground);
intent.setClassName(SETTINGS_PACKAGE_NAME,
ConfirmDeviceCredentialActivity.InternalActivity.class.getName());

View File

@@ -23,11 +23,13 @@ import android.util.Log
import androidx.lifecycle.LifecycleOwner
import com.android.settings.network.SubscriptionUtil
import com.android.settingslib.spa.framework.util.collectLatestWithLifecycle
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.asExecutor
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.callbackFlow
import kotlinx.coroutines.flow.conflate
import kotlinx.coroutines.flow.distinctUntilChanged
@@ -36,6 +38,8 @@ import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.flow.shareIn
private const val TAG = "SubscriptionRepository"
@@ -132,20 +136,7 @@ class SubscriptionRepository(private val context: Context) {
fun canDisablePhysicalSubscription() = subscriptionManager.canDisablePhysicalSubscription()
/** Flow for subscriptions changes. */
fun subscriptionsChangedFlow() = callbackFlow {
val listener = object : SubscriptionManager.OnSubscriptionsChangedListener() {
override fun onSubscriptionsChanged() {
trySend(Unit)
}
}
subscriptionManager.addOnSubscriptionsChangedListener(
Dispatchers.Default.asExecutor(),
listener,
)
awaitClose { subscriptionManager.removeOnSubscriptionsChangedListener(listener) }
}.conflate().onEach { Log.d(TAG, "subscriptions changed") }.flowOn(Dispatchers.Default)
fun subscriptionsChangedFlow() = getSharedSubscriptionsChangedFlow(context)
/** Flow of active subscription ids. */
fun activeSubscriptionIdListFlow(): Flow<List<Int>> =
@@ -172,6 +163,57 @@ class SubscriptionRepository(private val context: Context) {
flowOf(null)
}
}
companion object {
private lateinit var SharedSubscriptionsChangedFlow: Flow<Unit>
private fun getSharedSubscriptionsChangedFlow(context: Context): Flow<Unit> {
if (!this::SharedSubscriptionsChangedFlow.isInitialized) {
SharedSubscriptionsChangedFlow =
context.applicationContext
.requireSubscriptionManager()
.subscriptionsChangedFlow()
.shareIn(
scope = CoroutineScope(Dispatchers.Default),
started = SharingStarted.WhileSubscribed(),
replay = 1,
)
}
return SharedSubscriptionsChangedFlow
}
/**
* Flow for subscriptions changes.
*
* Note: Even the SubscriptionManager.addOnSubscriptionsChangedListener's doc says the
* SubscriptionManager.OnSubscriptionsChangedListener.onSubscriptionsChanged() method will
* also be invoked once initially when calling it, there still case that the
* onSubscriptionsChanged() method is not invoked initially. For example, when the
* onSubscriptionsChanged event never happens before, on a device never ever has any
* subscriptions.
*/
private fun SubscriptionManager.subscriptionsChangedFlow() =
callbackFlow {
val listener =
object : SubscriptionManager.OnSubscriptionsChangedListener() {
override fun onSubscriptionsChanged() {
trySend(Unit)
}
override fun onAddListenerFailed() {
close()
}
}
addOnSubscriptionsChangedListener(Dispatchers.Default.asExecutor(), listener)
awaitClose { removeOnSubscriptionsChangedListener(listener) }
}
.onStart { emit(Unit) } // Ensure this flow is never empty
.conflate()
.onEach { Log.d(TAG, "subscriptions changed") }
.flowOn(Dispatchers.Default)
}
}
val Context.subscriptionManager: SubscriptionManager?