Merge "Import translations. DO NOT MERGE ANYWHERE" into 24D1-dev
diff --git a/src/com/android/settings/datausage/lib/NetworkCycleBucketRepository.kt b/src/com/android/settings/datausage/lib/NetworkCycleBucketRepository.kt
index 7e3e183..01f1965 100644
--- a/src/com/android/settings/datausage/lib/NetworkCycleBucketRepository.kt
+++ b/src/com/android/settings/datausage/lib/NetworkCycleBucketRepository.kt
@@ -18,11 +18,10 @@
 
 import android.content.Context
 import android.net.NetworkTemplate
-import android.text.format.DateUtils
 import android.util.Range
+import com.android.settings.datausage.lib.NetworkCycleDataRepository.Companion.asFourWeeks
 import com.android.settings.datausage.lib.NetworkCycleDataRepository.Companion.bucketRange
 import com.android.settings.datausage.lib.NetworkCycleDataRepository.Companion.getCycles
-import com.android.settings.datausage.lib.NetworkCycleDataRepository.Companion.reverseBucketRange
 import com.android.settings.datausage.lib.NetworkStatsRepository.Companion.Bucket
 import com.android.settings.datausage.lib.NetworkStatsRepository.Companion.aggregate
 import com.android.settings.datausage.lib.NetworkStatsRepository.Companion.filterTime
@@ -39,16 +38,11 @@
         getCycles().map { aggregateUsage(it) }.filter { it.usage > 0 }
 
     private fun getCycles(): List<Range<Long>> =
-        networkCycleDataRepository.getPolicy()?.getCycles() ?: queryCyclesAsFourWeeks()
+        networkCycleDataRepository.getPolicy()?.getCycles().orEmpty()
+            .ifEmpty { queryCyclesAsFourWeeks() }
 
-    private fun queryCyclesAsFourWeeks(): List<Range<Long>> {
-        val timeRange = buckets.aggregate()?.timeRange ?: return emptyList()
-        return reverseBucketRange(
-            startTime = timeRange.lower,
-            endTime = timeRange.upper,
-            step = DateUtils.WEEK_IN_MILLIS * 4,
-        )
-    }
+    private fun queryCyclesAsFourWeeks(): List<Range<Long>> =
+        buckets.aggregate()?.timeRange.asFourWeeks()
 
     fun queryChartData(usageData: NetworkUsageData) = NetworkCycleChartData(
         total = usageData,
diff --git a/src/com/android/settings/datausage/lib/NetworkCycleDataRepository.kt b/src/com/android/settings/datausage/lib/NetworkCycleDataRepository.kt
index 31052ef..d55524c 100644
--- a/src/com/android/settings/datausage/lib/NetworkCycleDataRepository.kt
+++ b/src/com/android/settings/datausage/lib/NetworkCycleDataRepository.kt
@@ -42,16 +42,10 @@
     fun loadFirstCycle(): NetworkUsageData? = getCycles().firstOrNull()?.let { queryUsage(it) }
 
     override fun getCycles(): List<Range<Long>> =
-        getPolicy()?.getCycles() ?: queryCyclesAsFourWeeks()
+        getPolicy()?.getCycles().orEmpty().ifEmpty { queryCyclesAsFourWeeks() }
 
-    private fun queryCyclesAsFourWeeks(): List<Range<Long>> {
-        val timeRange = networkStatsRepository.getTimeRange() ?: return emptyList()
-        return reverseBucketRange(
-            startTime = timeRange.lower,
-            endTime = timeRange.upper,
-            step = DateUtils.WEEK_IN_MILLIS * 4,
-        )
-    }
+    private fun queryCyclesAsFourWeeks(): List<Range<Long>> =
+        networkStatsRepository.getTimeRange().asFourWeeks()
 
     override fun getPolicy(): NetworkPolicy? =
         with(NetworkPolicyEditor(policyManager)) {
@@ -59,7 +53,6 @@
             getPolicy(networkTemplate)
         }
 
-
     override fun queryUsage(range: Range<Long>) = NetworkUsageData(
         startTime = range.lower,
         endTime = range.upper,
@@ -71,6 +64,15 @@
             Range(it.lower.toInstant().toEpochMilli(), it.upper.toInstant().toEpochMilli())
         }.toList()
 
+        fun Range<Long>?.asFourWeeks(): List<Range<Long>> {
+            val timeRange = this ?: return emptyList()
+            return reverseBucketRange(
+                startTime = timeRange.lower,
+                endTime = timeRange.upper,
+                step = DateUtils.WEEK_IN_MILLIS * 4,
+            )
+        }
+
         fun bucketRange(startTime: Long, endTime: Long, step: Long): List<Range<Long>> =
             (startTime..endTime step step).zipWithNext(::Range)
 
diff --git a/src/com/android/settings/network/AirplaneModePreferenceController.java b/src/com/android/settings/network/AirplaneModePreferenceController.java
index b3fc517..54602c1 100644
--- a/src/com/android/settings/network/AirplaneModePreferenceController.java
+++ b/src/com/android/settings/network/AirplaneModePreferenceController.java
@@ -17,6 +17,9 @@
 
 import static android.provider.SettingsSlicesContract.KEY_AIRPLANE_MODE;
 
+import static com.android.settings.network.SatelliteWarningDialogActivity.EXTRA_TYPE_OF_SATELLITE_WARNING_DIALOG;
+import static com.android.settings.network.SatelliteWarningDialogActivity.TYPE_IS_AIRPLANE_MODE;
+
 import android.app.Activity;
 import android.content.ContentResolver;
 import android.content.Context;
@@ -25,6 +28,7 @@
 import android.net.Uri;
 import android.provider.SettingsSlicesContract;
 import android.telephony.TelephonyManager;
+import android.util.Log;
 
 import androidx.annotation.VisibleForTesting;
 import androidx.fragment.app.Fragment;
@@ -37,13 +41,20 @@
 import com.android.settings.core.TogglePreferenceController;
 import com.android.settingslib.core.lifecycle.LifecycleObserver;
 import com.android.settingslib.core.lifecycle.events.OnDestroy;
+import com.android.settingslib.core.lifecycle.events.OnResume;
 import com.android.settingslib.core.lifecycle.events.OnStart;
 import com.android.settingslib.core.lifecycle.events.OnStop;
 
-public class AirplaneModePreferenceController extends TogglePreferenceController
-        implements LifecycleObserver, OnStart, OnStop, OnDestroy,
-        AirplaneModeEnabler.OnAirplaneModeChangedListener {
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import java.util.concurrent.atomic.AtomicBoolean;
 
+public class AirplaneModePreferenceController extends TogglePreferenceController
+        implements LifecycleObserver, OnStart, OnResume, OnStop, OnDestroy,
+        AirplaneModeEnabler.OnAirplaneModeChangedListener {
+    private static final String TAG = AirplaneModePreferenceController.class.getSimpleName();
     public static final int REQUEST_CODE_EXIT_ECM = 1;
 
     /**
@@ -59,12 +70,15 @@
     private Fragment mFragment;
     private AirplaneModeEnabler mAirplaneModeEnabler;
     private TwoStatePreference mAirplaneModePreference;
+    private SatelliteRepository mSatelliteRepository;
+    @VisibleForTesting
+    AtomicBoolean mIsSatelliteOn = new AtomicBoolean(false);
 
     public AirplaneModePreferenceController(Context context, String key) {
         super(context, key);
-
         if (isAvailable(mContext)) {
             mAirplaneModeEnabler = new AirplaneModeEnabler(mContext, this);
+            mSatelliteRepository = new SatelliteRepository(mContext);
         }
     }
 
@@ -79,17 +93,27 @@
 
     @Override
     public boolean handlePreferenceTreeClick(Preference preference) {
-        if (KEY_AIRPLANE_MODE.equals(preference.getKey()) && isAvailable()
-                && mAirplaneModeEnabler.isInEcmMode()) {
+        if (KEY_AIRPLANE_MODE.equals(preference.getKey()) && isAvailable()) {
             // In ECM mode launch ECM app dialog
-            if (mFragment != null) {
-                mFragment.startActivityForResult(
-                        new Intent(TelephonyManager.ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS, null),
-                        REQUEST_CODE_EXIT_ECM);
+            if (mAirplaneModeEnabler.isInEcmMode()) {
+                if (mFragment != null) {
+                    mFragment.startActivityForResult(
+                            new Intent(TelephonyManager.ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS, null),
+                            REQUEST_CODE_EXIT_ECM);
+                }
+                return true;
             }
-            return true;
-        }
 
+            if (mIsSatelliteOn.get()) {
+                mContext.startActivity(
+                        new Intent(mContext, SatelliteWarningDialogActivity.class)
+                                .putExtra(
+                                        EXTRA_TYPE_OF_SATELLITE_WARNING_DIALOG,
+                                        TYPE_IS_AIRPLANE_MODE)
+                );
+                return true;
+            }
+        }
         return false;
     }
 
@@ -133,6 +157,17 @@
     }
 
     @Override
+    public void onResume() {
+        try {
+            mIsSatelliteOn.set(
+                    mSatelliteRepository.requestIsEnabled(Executors.newSingleThreadExecutor())
+                            .get(2000, TimeUnit.MILLISECONDS));
+        } catch (ExecutionException | TimeoutException | InterruptedException e) {
+            Log.e(TAG, "Error to get satellite status : " + e);
+        }
+    }
+
+    @Override
     public void onStop() {
         if (isAvailable()) {
             mAirplaneModeEnabler.stop();
@@ -163,7 +198,7 @@
 
     @Override
     public boolean setChecked(boolean isChecked) {
-        if (isChecked() == isChecked) {
+        if (isChecked() == isChecked || mIsSatelliteOn.get()) {
             return false;
         }
         if (isAvailable()) {
diff --git a/src/com/android/settings/network/MobileNetworkRepository.java b/src/com/android/settings/network/MobileNetworkRepository.java
index b0c85fc..0796dee 100644
--- a/src/com/android/settings/network/MobileNetworkRepository.java
+++ b/src/com/android/settings/network/MobileNetworkRepository.java
@@ -91,7 +91,6 @@
     private AirplaneModeObserver mAirplaneModeObserver;
     private DataRoamingObserver mDataRoamingObserver;
     private MetricsFeatureProvider mMetricsFeatureProvider;
-    private Map<Integer, MobileDataContentObserver> mDataContentObserverMap = new HashMap<>();
     private int mPhysicalSlotIndex = SubscriptionManager.INVALID_SIM_SLOT_INDEX;
     private int mLogicalSlotIndex = SubscriptionManager.INVALID_SIM_SLOT_INDEX;
     private int mCardState = UiccSlotInfo.CARD_STATE_INFO_ABSENT;
@@ -209,6 +208,9 @@
      */
     public void addRegister(LifecycleOwner lifecycleOwner,
             MobileNetworkCallback mobileNetworkCallback, int subId) {
+        if (DEBUG) {
+            Log.d(TAG, "addRegister by SUB ID " + subId);
+        }
         if (sCallbacks.isEmpty()) {
             mSubscriptionManager.addOnSubscriptionsChangedListener(mContext.getMainExecutor(),
                     this);
@@ -222,7 +224,6 @@
         observeAllUiccInfo(lifecycleOwner);
         observeAllMobileNetworkInfo(lifecycleOwner);
         if (subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
-            addRegisterBySubId(subId);
             createTelephonyManagerBySubId(subId);
             mDataRoamingObserver.register(mContext, subId);
         }
@@ -231,25 +232,12 @@
         sendAvailableSubInfoCache(mobileNetworkCallback);
     }
 
-    public void addRegisterBySubId(int subId) {
-        MobileDataContentObserver dataContentObserver = new MobileDataContentObserver(
-                new Handler(Looper.getMainLooper()));
-        dataContentObserver.setOnMobileDataChangedListener(() -> {
-            sExecutor.execute(() -> {
-                insertMobileNetworkInfo(mContext, subId,
-                        getTelephonyManagerBySubId(mContext, subId));
-            });
-        });
-        dataContentObserver.register(mContext, subId);
-        mDataContentObserverMap.put(subId, dataContentObserver);
-    }
-
     private void createTelephonyManagerBySubId(int subId) {
         if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
             return;
         }
         PhoneCallStateTelephonyCallback
-                telephonyCallback = new PhoneCallStateTelephonyCallback();
+                telephonyCallback = new PhoneCallStateTelephonyCallback(subId);
         TelephonyManager telephonyManager = mContext.getSystemService(
                 TelephonyManager.class).createForSubscriptionId(subId);
         telephonyManager.registerTelephonyCallback(mContext.getMainExecutor(),
@@ -288,10 +276,6 @@
                 }
             }
         }
-        if (mDataContentObserverMap.containsKey(subId)) {
-            mDataContentObserverMap.get(subId).unRegister(mContext);
-            mDataContentObserverMap.remove(subId);
-        }
     }
 
     public void removeRegister(MobileNetworkCallback mobileNetworkCallback) {
@@ -300,10 +284,6 @@
             mSubscriptionManager.removeOnSubscriptionsChangedListener(this);
             mAirplaneModeObserver.unRegister(mContext);
             mDataRoamingObserver.unRegister(mContext);
-            mDataContentObserverMap.forEach((id, observer) -> {
-                observer.unRegister(mContext);
-            });
-            mDataContentObserverMap.clear();
 
             mTelephonyManagerMap.forEach((id, manager) -> {
                 TelephonyCallback callback = mTelephonyCallbackMap.get(id);
@@ -764,7 +744,14 @@
     }
 
     private class PhoneCallStateTelephonyCallback extends TelephonyCallback implements
-            TelephonyCallback.CallStateListener {
+            TelephonyCallback.CallStateListener,
+            TelephonyCallback.UserMobileDataStateListener {
+
+        private int mSubId;
+
+        public PhoneCallStateTelephonyCallback(int subId) {
+            mSubId = subId;
+        }
 
         @Override
         public void onCallStateChanged(int state) {
@@ -772,6 +759,15 @@
                 callback.onCallStateChanged(state);
             }
         }
+
+        @Override
+        public void onUserMobileDataStateChanged(boolean enabled) {
+            Log.d(TAG, "onUserMobileDataStateChanged enabled " + enabled + " on SUB " + mSubId);
+            sExecutor.execute(() -> {
+                insertMobileNetworkInfo(mContext, mSubId,
+                        getTelephonyManagerBySubId(mContext, mSubId));
+            });
+        }
     }
 
     /**
diff --git a/src/com/android/settings/network/SatelliteWarningDialogActivity.kt b/src/com/android/settings/network/SatelliteWarningDialogActivity.kt
index a0d494c..0702e4f 100644
--- a/src/com/android/settings/network/SatelliteWarningDialogActivity.kt
+++ b/src/com/android/settings/network/SatelliteWarningDialogActivity.kt
@@ -41,7 +41,7 @@
     }
 
     override fun getDialogWindowType(): Int {
-        return WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW
+        return WindowManager.LayoutParams.LAST_APPLICATION_WINDOW
     }
 
     @Composable
diff --git a/src/com/android/settings/network/telephony/DefaultSubscriptionController.java b/src/com/android/settings/network/telephony/DefaultSubscriptionController.java
index 03ce7f6..96c39f2 100644
--- a/src/com/android/settings/network/telephony/DefaultSubscriptionController.java
+++ b/src/com/android/settings/network/telephony/DefaultSubscriptionController.java
@@ -100,9 +100,6 @@
         mMobileNetworkRepository.addRegister(mLifecycleOwner, this,
                 SubscriptionManager.INVALID_SUBSCRIPTION_ID);
         mMobileNetworkRepository.updateEntity();
-        // Can not get default subId from database until get the callback, add register by subId
-        // later.
-        mMobileNetworkRepository.addRegisterBySubId(getDefaultSubscriptionId());
         mDataSubscriptionChangedReceiver.registerReceiver();
     }
 
diff --git a/src/com/android/settings/wifi/WifiEnabler.java b/src/com/android/settings/wifi/WifiEnabler.java
index 794587d..d1cf7d6 100644
--- a/src/com/android/settings/wifi/WifiEnabler.java
+++ b/src/com/android/settings/wifi/WifiEnabler.java
@@ -16,6 +16,9 @@
 
 package com.android.settings.wifi;
 
+import static com.android.settings.network.SatelliteWarningDialogActivity.EXTRA_TYPE_OF_SATELLITE_WARNING_DIALOG;
+import static com.android.settings.network.SatelliteWarningDialogActivity.TYPE_IS_WIFI;
+
 import android.app.settings.SettingsEnums;
 import android.content.BroadcastReceiver;
 import android.content.Context;
@@ -27,19 +30,26 @@
 import android.net.wifi.WifiInfo;
 import android.net.wifi.WifiManager;
 import android.provider.Settings;
+import android.util.Log;
 import android.widget.Toast;
 
 import androidx.annotation.VisibleForTesting;
 
 import com.android.settings.R;
+import com.android.settings.network.SatelliteRepository;
+import com.android.settings.network.SatelliteWarningDialogActivity;
 import com.android.settings.widget.SwitchWidgetController;
 import com.android.settingslib.WirelessUtils;
 import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
 
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
 import java.util.concurrent.atomic.AtomicBoolean;
 
 public class WifiEnabler implements SwitchWidgetController.OnSwitchChangeListener  {
-
+    private static final String TAG = WifiEnabler.class.getSimpleName();
     private final SwitchWidgetController mSwitchWidget;
     private final WifiManager mWifiManager;
     private final ConnectivityManager mConnectivityManager;
@@ -48,7 +58,9 @@
     private Context mContext;
     private boolean mListeningToOnSwitchChange = false;
     private AtomicBoolean mConnected = new AtomicBoolean(false);
-
+    private SatelliteRepository mSatelliteRepository;
+    @VisibleForTesting
+    AtomicBoolean mIsSatelliteOn = new AtomicBoolean(false);
 
     private boolean mStateMachineEvent;
     private final IntentFilter mIntentFilter;
@@ -93,7 +105,7 @@
         // The order matters! We really should not depend on this. :(
         mIntentFilter.addAction(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION);
         mIntentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
-
+        mSatelliteRepository = new SatelliteRepository(context);
         setupSwitchController();
     }
 
@@ -124,6 +136,14 @@
             mSwitchWidget.startListening();
             mListeningToOnSwitchChange = true;
         }
+        // Refresh satellite mode status.
+        try {
+            mIsSatelliteOn.set(
+                    mSatelliteRepository.requestIsEnabled(Executors.newSingleThreadExecutor())
+                            .get(2000, TimeUnit.MILLISECONDS));
+        } catch (ExecutionException | TimeoutException | InterruptedException e) {
+            Log.e(TAG, "Error to get satellite status : " + e);
+        }
     }
 
     public void pause() {
@@ -185,6 +205,18 @@
         if (mStateMachineEvent) {
             return true;
         }
+
+        // Show dialog and do nothing under satellite mode.
+        if (mIsSatelliteOn.get()) {
+            mContext.startActivity(
+                    new Intent(mContext, SatelliteWarningDialogActivity.class)
+                            .putExtra(
+                                    EXTRA_TYPE_OF_SATELLITE_WARNING_DIALOG,
+                                    TYPE_IS_WIFI)
+            );
+            return false;
+        }
+
         // Show toast message if Wi-Fi is not allowed in airplane mode
         if (isChecked && !WirelessUtils.isRadioAllowed(mContext, Settings.Global.RADIO_WIFI)) {
             Toast.makeText(mContext, R.string.wifi_in_airplane_mode, Toast.LENGTH_SHORT).show();
diff --git a/src/com/android/settings/wifi/slice/WifiSlice.java b/src/com/android/settings/wifi/slice/WifiSlice.java
index f75fe11..599bf6b 100644
--- a/src/com/android/settings/wifi/slice/WifiSlice.java
+++ b/src/com/android/settings/wifi/slice/WifiSlice.java
@@ -52,6 +52,7 @@
 import com.android.settings.Utils;
 import com.android.settings.core.SubSettingLauncher;
 import com.android.settings.network.NetworkProviderSettings;
+import com.android.settings.network.SatelliteRepository;
 import com.android.settings.network.WifiSwitchPreferenceController;
 import com.android.settings.slices.CustomSliceable;
 import com.android.settings.slices.SliceBackgroundWorker;
@@ -66,6 +67,10 @@
 import java.util.Arrays;
 import java.util.List;
 import java.util.Set;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
 import java.util.stream.Collectors;
 
 /**
@@ -225,7 +230,8 @@
                 .setAccentColor(COLOR_NOT_TINTED)
                 .setKeywords(getKeywords())
                 .addRow(getHeaderRow(isWifiEnabled, wifiSliceItem));
-        if (!isWiFiPermissionGranted || !mWifiRestriction.isChangeWifiStateAllowed(mContext)) {
+        if (!isWiFiPermissionGranted || !mWifiRestriction.isChangeWifiStateAllowed(mContext)
+                || isSatelliteOn()) {
             return builder;
         }
 
@@ -416,4 +422,17 @@
             return WifiEnterpriseRestrictionUtils.isChangeWifiStateAllowed(context);
         }
     }
+
+    private boolean isSatelliteOn() {
+        SatelliteRepository satelliteRepository = new SatelliteRepository(mContext);
+        boolean isSatelliteOn = false;
+        try {
+            isSatelliteOn =
+                    satelliteRepository.requestIsEnabled(Executors.newSingleThreadExecutor())
+                            .get(2000, TimeUnit.MILLISECONDS);
+        } catch (ExecutionException | TimeoutException | InterruptedException e) {
+            Log.e(TAG, "Error to get satellite status : " + e);
+        }
+        return isSatelliteOn;
+    }
 }
diff --git a/tests/robotests/src/com/android/settings/wifi/WifiEnablerTest.java b/tests/robotests/src/com/android/settings/wifi/WifiEnablerTest.java
index 65cc811..6980e8a 100644
--- a/tests/robotests/src/com/android/settings/wifi/WifiEnablerTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/WifiEnablerTest.java
@@ -18,12 +18,15 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import android.content.Context;
 import android.net.ConnectivityManager;
 import android.net.wifi.WifiManager;
+import android.util.AndroidRuntimeException;
 
 import com.android.settings.testutils.shadow.ShadowRestrictedLockUtilsInternal;
 import com.android.settings.widget.SwitchWidgetController;
@@ -65,4 +68,17 @@
 
         assertThat(mEnabler.onSwitchToggled(true)).isTrue();
     }
+
+    @Test
+    public void onSwitchToggled_satelliteOn_startWarningActivity() {
+        mEnabler.mIsSatelliteOn.set(true);
+
+        try {
+            mEnabler.onSwitchToggled(true);
+        } catch (AndroidRuntimeException e) {
+            // Catch exception of starting activity .
+        }
+
+        verify(mContext).startActivity(any());
+    }
 }
diff --git a/tests/spa_unit/src/com/android/settings/datausage/lib/NetworkCycleBucketRepositoryTest.kt b/tests/spa_unit/src/com/android/settings/datausage/lib/NetworkCycleBucketRepositoryTest.kt
index f83b85f..81b57c9 100644
--- a/tests/spa_unit/src/com/android/settings/datausage/lib/NetworkCycleBucketRepositoryTest.kt
+++ b/tests/spa_unit/src/com/android/settings/datausage/lib/NetworkCycleBucketRepositoryTest.kt
@@ -42,6 +42,13 @@
 
     private val mockNetworkCycleDataRepository = mock<NetworkCycleDataRepository>()
 
+    private fun createRepository(buckets: List<Bucket>) = NetworkCycleBucketRepository(
+        context = context,
+        networkTemplate = template,
+        buckets = buckets,
+        networkCycleDataRepository = mockNetworkCycleDataRepository,
+    )
+
     @Test
     fun loadCycles_byPolicy() {
         val policy = mock<NetworkPolicy> {
@@ -52,9 +59,7 @@
         mockNetworkCycleDataRepository.stub {
             on { getPolicy() } doReturn policy
         }
-        val repository = NetworkCycleBucketRepository(
-            context = context,
-            networkTemplate = template,
+        val repository = createRepository(
             buckets = listOf(
                 Bucket(
                     uid = 0,
@@ -62,8 +67,7 @@
                     startTimeStamp = CYCLE1_START_TIME,
                     endTimeStamp = CYCLE1_END_TIME,
                 )
-            ),
-            networkCycleDataRepository = mockNetworkCycleDataRepository,
+            )
         )
 
         val cycles = repository.loadCycles()
@@ -78,13 +82,14 @@
     }
 
     @Test
-    fun loadCycles_asFourWeeks() {
-        mockNetworkCycleDataRepository.stub {
-            on { getPolicy() } doReturn null
+    fun loadCycles_policyHasNoCycle_asFourWeeks() {
+        val policy = mock<NetworkPolicy> {
+            on { cycleIterator() } doReturn emptyList<Range<ZonedDateTime>>().iterator()
         }
-        val repository = NetworkCycleBucketRepository(
-            context = context,
-            networkTemplate = template,
+        mockNetworkCycleDataRepository.stub {
+            on { getPolicy() } doReturn policy
+        }
+        val repository = createRepository(
             buckets = listOf(
                 Bucket(
                     uid = 0,
@@ -92,8 +97,34 @@
                     startTimeStamp = CYCLE2_START_TIME,
                     endTimeStamp = CYCLE2_END_TIME,
                 )
+            )
+        )
+
+        val cycles = repository.loadCycles()
+
+        assertThat(cycles).containsExactly(
+            NetworkUsageData(
+                startTime = CYCLE2_END_TIME - DateUtils.WEEK_IN_MILLIS * 4,
+                endTime = CYCLE2_END_TIME,
+                usage = CYCLE2_BYTES,
             ),
-            networkCycleDataRepository = mockNetworkCycleDataRepository,
+        )
+    }
+
+    @Test
+    fun loadCycles_noPolicy_asFourWeeks() {
+        mockNetworkCycleDataRepository.stub {
+            on { getPolicy() } doReturn null
+        }
+        val repository = createRepository(
+            buckets = listOf(
+                Bucket(
+                    uid = 0,
+                    bytes = CYCLE2_BYTES,
+                    startTimeStamp = CYCLE2_START_TIME,
+                    endTimeStamp = CYCLE2_END_TIME,
+                )
+            )
         )
 
         val cycles = repository.loadCycles()
@@ -114,9 +145,7 @@
             endTime = CYCLE4_END_TIME,
             usage = CYCLE3_BYTES + CYCLE4_BYTES,
         )
-        val repository = NetworkCycleBucketRepository(
-            context = context,
-            networkTemplate = template,
+        val repository = createRepository(
             buckets = listOf(
                 Bucket(
                     uid = 0,
@@ -131,7 +160,6 @@
                     endTimeStamp = CYCLE4_END_TIME,
                 ),
             ),
-            networkCycleDataRepository = mockNetworkCycleDataRepository,
         )
 
         val summary = repository.queryChartData(cycle)
diff --git a/tests/spa_unit/src/com/android/settings/datausage/lib/NetworkCycleDataRepositoryTest.kt b/tests/spa_unit/src/com/android/settings/datausage/lib/NetworkCycleDataRepositoryTest.kt
index 77fe843..c011af2 100644
--- a/tests/spa_unit/src/com/android/settings/datausage/lib/NetworkCycleDataRepositoryTest.kt
+++ b/tests/spa_unit/src/com/android/settings/datausage/lib/NetworkCycleDataRepositoryTest.kt
@@ -25,6 +25,7 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import com.android.settings.testutils.zonedDateTime
 import com.google.common.truth.Truth.assertThat
+import java.time.ZonedDateTime
 import kotlinx.coroutines.test.runTest
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -77,7 +78,28 @@
     }
 
     @Test
-    fun loadFirstCycle_asFourWeeks() = runTest {
+    fun loadFirstCycle_policyHasNoCycle_asFourWeeks() = runTest {
+        val policy = mock<NetworkPolicy> {
+            on { cycleIterator() } doReturn emptyList<Range<ZonedDateTime>>().iterator()
+        }
+        doReturn(policy).whenever(repository).getPolicy()
+        mockNetworkStatsRepository.stub {
+            on { getTimeRange() } doReturn Range(CYCLE2_START_TIME, CYCLE2_END_TIME)
+        }
+
+        val firstCycle = repository.loadFirstCycle()
+
+        assertThat(firstCycle).isEqualTo(
+            NetworkUsageData(
+                startTime = CYCLE2_END_TIME - DateUtils.WEEK_IN_MILLIS * 4,
+                endTime = CYCLE2_END_TIME,
+                usage = CYCLE2_BYTES,
+            ),
+        )
+    }
+
+    @Test
+    fun loadFirstCycle_noPolicy_asFourWeeks() = runTest {
         doReturn(null).whenever(repository).getPolicy()
         mockNetworkStatsRepository.stub {
             on { getTimeRange() } doReturn Range(CYCLE2_START_TIME, CYCLE2_END_TIME)
diff --git a/tests/unit/src/com/android/settings/network/AirplaneModePreferenceControllerTest.java b/tests/unit/src/com/android/settings/network/AirplaneModePreferenceControllerTest.java
index 1d6a624..7612805 100644
--- a/tests/unit/src/com/android/settings/network/AirplaneModePreferenceControllerTest.java
+++ b/tests/unit/src/com/android/settings/network/AirplaneModePreferenceControllerTest.java
@@ -16,10 +16,14 @@
 
 package com.android.settings.network;
 
+import static android.provider.SettingsSlicesContract.KEY_AIRPLANE_MODE;
+
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import android.content.ContentResolver;
@@ -28,6 +32,7 @@
 import android.os.Looper;
 import android.provider.Settings;
 import android.provider.SettingsSlicesContract;
+import android.util.AndroidRuntimeException;
 
 import androidx.preference.PreferenceManager;
 import androidx.preference.PreferenceScreen;
@@ -73,12 +78,12 @@
         mResolver = mContext.getContentResolver();
         doReturn(mPackageManager).when(mContext).getPackageManager();
         mController = new AirplaneModePreferenceController(mContext,
-                SettingsSlicesContract.KEY_AIRPLANE_MODE);
+                KEY_AIRPLANE_MODE);
 
         mPreferenceManager = new PreferenceManager(mContext);
         mScreen = mPreferenceManager.createPreferenceScreen(mContext);
         mPreference = new RestrictedSwitchPreference(mContext);
-        mPreference.setKey(SettingsSlicesContract.KEY_AIRPLANE_MODE);
+        mPreference.setKey(KEY_AIRPLANE_MODE);
         mScreen.addPreference(mPreference);
         mController.setFragment(null);
     }
@@ -167,4 +172,18 @@
     public void isPublicSlice_returnsTrue() {
         assertThat(mController.isPublicSlice()).isTrue();
     }
+
+    @Test
+    public void handlePreferenceTreeClick_satelliteOn_startWarningActivity() {
+        mController.mIsSatelliteOn.set(true);
+        when(mAirplaneModeEnabler.isInEcmMode()).thenReturn(false);
+
+        try {
+            mController.handlePreferenceTreeClick(mPreference);
+        } catch (AndroidRuntimeException e) {
+            // Catch exception of starting activity .
+        }
+
+        verify(mContext).startActivity(any());
+    }
 }