Merge "Improve content description of data usage chart" into main
diff --git a/res/values/strings.xml b/res/values/strings.xml
index b54b822..660cd96 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -5727,7 +5727,9 @@
 
     <!-- Category title for battery background settings in power usage detail page [CHAR LIMIT=NONE] -->
     <string name="manager_battery_usage_category_title">Manage battery usage</string>
-    <!-- Title for allow background usage [CHAR LIMIT=NONE] -->
+    <!-- Title for allow background usage settings page [CHAR LIMIT=NONE] -->
+    <string name="manager_battery_usage_allow_background_usage_settings_title">Allow background usage</string>
+    <!-- Title for the allow background usage toggle [CHAR LIMIT=NONE] -->
     <string name="manager_battery_usage_allow_background_usage_title">Allow background usage</string>
     <!-- Summary for allow background usage [CHAR LIMIT=NONE] -->
     <string name="manager_battery_usage_allow_background_usage_summary">Enable for real-time updates, disable to save battery</string>
diff --git a/res/xml/power_background_usage_detail.xml b/res/xml/power_background_usage_detail.xml
index fb089fd..5c7b6a5 100644
--- a/res/xml/power_background_usage_detail.xml
+++ b/res/xml/power_background_usage_detail.xml
@@ -18,7 +18,7 @@
 <PreferenceScreen
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:settings="http://schemas.android.com/apk/res-auto"
-    android:title="@string/manager_battery_usage_allow_background_usage_title">
+    android:title="@string/manager_battery_usage_allow_background_usage_settings_title">
 
     <com.android.settingslib.widget.LayoutPreference
         android:key="header_view"
diff --git a/src/com/android/settings/biometrics/face/FaceEnrollIntroductionInternal.java b/src/com/android/settings/biometrics/face/FaceEnrollIntroductionInternal.java
index 7dd29da..51d3a3a 100644
--- a/src/com/android/settings/biometrics/face/FaceEnrollIntroductionInternal.java
+++ b/src/com/android/settings/biometrics/face/FaceEnrollIntroductionInternal.java
@@ -16,8 +16,34 @@
 
 package com.android.settings.biometrics.face;
 
+import static com.android.settings.Utils.SETTINGS_PACKAGE_NAME;
+
+import android.content.Intent;
+import android.os.Bundle;
+
+import androidx.fragment.app.FragmentActivity;
+
 /**
  * Wrapper of {@link FaceEnrollIntroduction} to use with a pre-defined task affinity.
+ *
+ * <p>Trampolines over to FaceEnrollIntroduction - doing this as a trampoline rather than having
+ * this activity extend FaceEnrollIntroduction works around b/331157120.
  */
-public class FaceEnrollIntroductionInternal extends FaceEnrollIntroduction {
+public class FaceEnrollIntroductionInternal extends FragmentActivity {
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        if (isFinishing()) {
+            return;
+        }
+
+        // Copy our intent to grab all extras. Drop flags so we don't start new tasks twice.
+        Intent trampoline = new Intent(getIntent());
+        trampoline.setFlags(0);
+
+        // Trampoline to the intended activity, and finish
+        trampoline.setClassName(SETTINGS_PACKAGE_NAME, FaceEnrollIntroduction.class.getName());
+        startActivity(trampoline);
+        finish();
+    }
 }
diff --git a/src/com/android/settings/network/apn/ApnEditPageProvider.kt b/src/com/android/settings/network/apn/ApnEditPageProvider.kt
index a287b84..71fe4d6 100644
--- a/src/com/android/settings/network/apn/ApnEditPageProvider.kt
+++ b/src/com/android/settings/network/apn/ApnEditPageProvider.kt
@@ -27,6 +27,7 @@
 import androidx.compose.material3.MaterialTheme
 import androidx.compose.material3.Text
 import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
 import androidx.compose.runtime.MutableState
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableStateOf
@@ -39,6 +40,7 @@
 import androidx.navigation.NavType
 import androidx.navigation.navArgument
 import com.android.settings.R
+import com.android.settings.network.telephony.SubscriptionRepository
 import com.android.settingslib.spa.framework.common.SettingsPageProvider
 import com.android.settingslib.spa.framework.compose.LocalNavController
 import com.android.settingslib.spa.framework.theme.SettingsDimension
@@ -78,6 +80,18 @@
             mutableStateOf(apnDataInit)
         }
         ApnPage(apnDataInit, apnDataCur, uriInit)
+        SubscriptionNotEnabledEffect(subId)
+    }
+
+    @Composable
+    private fun SubscriptionNotEnabledEffect(subId: Int) {
+        val context = LocalContext.current
+        val navController = LocalNavController.current
+        LaunchedEffect(subId) {
+            SubscriptionRepository(context).isSubscriptionEnabledFlow(subId).collect { isEnabled ->
+                if (!isEnabled) navController.navigateBack()
+            }
+        }
     }
 
     fun getRoute(
diff --git a/src/com/android/settings/network/apn/ApnSettings.java b/src/com/android/settings/network/apn/ApnSettings.java
index be90653..80239cb 100644
--- a/src/com/android/settings/network/apn/ApnSettings.java
+++ b/src/com/android/settings/network/apn/ApnSettings.java
@@ -52,8 +52,11 @@
 import android.view.MenuInflater;
 import android.view.MenuItem;
 import android.view.MotionEvent;
+import android.view.View;
 import android.widget.Toast;
 
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
 import androidx.preference.Preference;
 import androidx.preference.PreferenceGroup;
 
@@ -61,9 +64,12 @@
 import com.android.settings.RestrictedSettingsFragment;
 import com.android.settings.flags.Flags;
 import com.android.settings.network.SubscriptionUtil;
+import com.android.settings.network.telephony.SubscriptionRepository;
 import com.android.settings.spa.SpaActivity;
 import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
 
+import kotlin.Unit;
+
 import java.util.ArrayList;
 
 /** Handle each different apn setting. */
@@ -92,13 +98,6 @@
             Telephony.Carriers.EDITED_STATUS,
     };
 
-    /** Copied from {@code com.android.internal.telephony.TelephonyIntents} */
-    private static final String ACTION_SIM_STATE_CHANGED =
-            "android.intent.action.SIM_STATE_CHANGED";
-    /** Copied from {@code com.android.internal.telephony.IccCardConstants} */
-    public static final String INTENT_KEY_ICC_STATE = "ss";
-    public static final String INTENT_VALUE_ICC_ABSENT = "ABSENT";
-
     private static final int ID_INDEX = 0;
     private static final int NAME_INDEX = 1;
     private static final int APN_INDEX = 2;
@@ -162,16 +161,7 @@
     private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
-            String action = intent.getAction();
-            if (ACTION_SIM_STATE_CHANGED.equals(action)
-                    && intent.getStringExtra(INTENT_KEY_ICC_STATE)
-                    .equals(INTENT_VALUE_ICC_ABSENT)) {
-                final SubscriptionManager sm = context.getSystemService(SubscriptionManager.class);
-                if (sm != null && !sm.isActiveSubscriptionId(mSubId)) {
-                    Log.d(TAG, "Due to SIM absent, closes APN settings page");
-                    finish();
-                }
-            } else if (intent.getAction().equals(
+            if (intent.getAction().equals(
                     TelephonyManager.ACTION_SUBSCRIPTION_CARRIER_IDENTITY_CHANGED)) {
                 if (mRestoreDefaultApnMode) {
                     return;
@@ -223,7 +213,6 @@
         mPhoneId = SubscriptionUtil.getPhoneId(activity, mSubId);
         mIntentFilter = new IntentFilter();
         mIntentFilter.addAction(TelephonyManager.ACTION_SUBSCRIPTION_CARRIER_IDENTITY_CHANGED);
-        mIntentFilter.addAction(ACTION_SIM_STATE_CHANGED);
 
         setIfOnlyAvailableForAdmins(true);
 
@@ -264,6 +253,20 @@
     }
 
     @Override
+    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
+        super.onViewCreated(view, savedInstanceState);
+
+        new SubscriptionRepository(requireContext())
+                .collectSubscriptionEnabled(mSubId, getViewLifecycleOwner(), (isEnabled) -> {
+                    if (!isEnabled) {
+                        Log.d(TAG, "Due to subscription not enabled, closes APN settings page");
+                        finish();
+                    }
+                    return Unit.INSTANCE;
+                });
+    }
+
+    @Override
     public void onResume() {
         super.onResume();
 
diff --git a/src/com/android/settings/network/telephony/SubscriptionRepository.kt b/src/com/android/settings/network/telephony/SubscriptionRepository.kt
index b0a39ec..938f4d8 100644
--- a/src/com/android/settings/network/telephony/SubscriptionRepository.kt
+++ b/src/com/android/settings/network/telephony/SubscriptionRepository.kt
@@ -20,7 +20,9 @@
 import android.telephony.SubscriptionInfo
 import android.telephony.SubscriptionManager
 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.Dispatchers
 import kotlinx.coroutines.asExecutor
 import kotlinx.coroutines.channels.awaitClose
@@ -43,6 +45,16 @@
         context.getSelectableSubscriptionInfoList()
 
     fun isSubscriptionEnabledFlow(subId: Int) = context.isSubscriptionEnabledFlow(subId)
+
+    /** TODO: Move this to UI layer, when UI layer migrated to Kotlin. */
+    fun collectSubscriptionEnabled(
+        subId: Int,
+        lifecycleOwner: LifecycleOwner,
+        action: (Boolean) -> Unit,
+    ) {
+        isSubscriptionEnabledFlow(subId).collectLatestWithLifecycle(lifecycleOwner, action = action)
+    }
+
 }
 
 val Context.subscriptionManager: SubscriptionManager?
@@ -52,7 +64,8 @@
 
 fun Context.isSubscriptionEnabledFlow(subId: Int) = subscriptionsChangedFlow().map {
     subscriptionManager?.isSubscriptionEnabled(subId) ?: false
-}.flowOn(Dispatchers.Default)
+}.conflate().onEach { Log.d(TAG, "[$subId] isSubscriptionEnabledFlow: $it") }
+    .flowOn(Dispatchers.Default)
 
 fun Context.phoneNumberFlow(subscriptionInfo: SubscriptionInfo) = subscriptionsChangedFlow().map {
     SubscriptionUtil.getFormattedPhoneNumber(this, subscriptionInfo)