New BillingCycleRepository

Migrate BillingCyclePreference to BillingCycleRepository first, will
also migrate DataUsageList in future cl.

Also fix an issue that the BillingCyclePreference initial enable state
not set.

Bug: 290856342
Test: manual - on mobile settings
Test: unit test
Change-Id: Idd171fefbc30763010afb7bfb68543612f7b9b1a
diff --git a/src/com/android/settings/datausage/BillingCyclePreference.java b/src/com/android/settings/datausage/BillingCyclePreference.java
deleted file mode 100644
index 1bd2be8..0000000
--- a/src/com/android/settings/datausage/BillingCyclePreference.java
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * Copyright (C) 2016 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.datausage;
-
-import android.app.settings.SettingsEnums;
-import android.content.Context;
-import android.content.Intent;
-import android.net.NetworkTemplate;
-import android.os.Bundle;
-import android.os.RemoteException;
-import android.telephony.TelephonyManager;
-import android.telephony.data.ApnSetting;
-import android.util.AttributeSet;
-
-import androidx.preference.Preference;
-
-import com.android.settings.R;
-import com.android.settings.core.SubSettingLauncher;
-import com.android.settings.network.MobileDataEnabledListener;
-
-/**
- * Preference which displays billing cycle of subscription
- */
-public class BillingCyclePreference extends Preference
-        implements TemplatePreference, MobileDataEnabledListener.Client {
-
-    private NetworkTemplate mTemplate;
-    private NetworkServices mServices;
-    private int mSubId;
-    private MobileDataEnabledListener mListener;
-
-    /**
-     * Preference constructor
-     *
-     * @param context Context of preference
-     * @param arrts The attributes of the XML tag that is inflating the preference
-     */
-    public BillingCyclePreference(Context context, AttributeSet attrs) {
-        super(context, attrs);
-        mListener = new MobileDataEnabledListener(context, this);
-    }
-
-    @Override
-    public void onAttached() {
-        super.onAttached();
-        mListener.start(mSubId);
-    }
-
-    @Override
-    public void onDetached() {
-        mListener.stop();
-        super.onDetached();
-    }
-
-    @Override
-    public void setTemplate(NetworkTemplate template, int subId,
-            NetworkServices services) {
-        mTemplate = template;
-        mSubId = subId;
-        mServices = services;
-        setSummary(null);
-
-        setIntent(getIntent());
-    }
-
-    private void updateEnabled() {
-        try {
-            setEnabled(mServices.mNetworkService.isBandwidthControlEnabled()
-                    && mServices.mTelephonyManager.createForSubscriptionId(mSubId)
-                            .isDataEnabledForReason(TelephonyManager.DATA_ENABLED_REASON_USER)
-                    && mServices.mUserManager.isAdminUser());
-        } catch (RemoteException e) {
-            setEnabled(false);
-        }
-    }
-
-    @Override
-    public Intent getIntent() {
-        final Bundle args = new Bundle();
-        args.putParcelable(DataUsageList.EXTRA_NETWORK_TEMPLATE, mTemplate);
-        return new SubSettingLauncher(getContext())
-                .setDestination(BillingCycleSettings.class.getName())
-                .setArguments(args)
-                .setTitleRes(R.string.billing_cycle)
-                .setSourceMetricsCategory(SettingsEnums.PAGE_UNKNOWN)
-                .toIntent();
-    }
-
-    /**
-     * Implementation of {@code MobileDataEnabledListener.Client}
-     */
-    public void onMobileDataEnabledChange() {
-        updateEnabled();
-    }
-}
diff --git a/src/com/android/settings/datausage/BillingCyclePreference.kt b/src/com/android/settings/datausage/BillingCyclePreference.kt
new file mode 100644
index 0000000..bdae4fa
--- /dev/null
+++ b/src/com/android/settings/datausage/BillingCyclePreference.kt
@@ -0,0 +1,80 @@
+/*
+ * 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.datausage
+
+import android.app.settings.SettingsEnums
+import android.content.Context
+import android.content.Intent
+import android.net.NetworkTemplate
+import android.os.Bundle
+import android.util.AttributeSet
+import androidx.preference.Preference
+import com.android.settings.R
+import com.android.settings.core.SubSettingLauncher
+import com.android.settings.datausage.TemplatePreference.NetworkServices
+import com.android.settings.datausage.lib.BillingCycleRepository
+import com.android.settings.network.MobileDataEnabledListener
+
+/**
+ * Preference which displays billing cycle of subscription
+ *
+ * @param context Context of preference
+ * @param attrs   The attributes of the XML tag that is inflating the preference
+ */
+class BillingCyclePreference @JvmOverloads constructor(
+    context: Context,
+    attrs: AttributeSet?,
+    private val repository: BillingCycleRepository = BillingCycleRepository(context),
+) : Preference(context, attrs), TemplatePreference {
+    private lateinit var template: NetworkTemplate
+    private var subId = 0
+
+    private val listener = MobileDataEnabledListener(context) {
+        updateEnabled()
+    }
+
+    override fun setTemplate(template: NetworkTemplate, subId: Int, services: NetworkServices?) {
+        this.template = template
+        this.subId = subId
+        summary = null
+        updateEnabled()
+    }
+
+    override fun onAttached() {
+        super.onAttached()
+        listener.start(subId)
+    }
+
+    override fun onDetached() {
+        listener.stop()
+        super.onDetached()
+    }
+
+    private fun updateEnabled() {
+        isEnabled = repository.isModifiable(subId)
+    }
+
+    override fun getIntent(): Intent {
+        val args = Bundle().apply {
+            putParcelable(DataUsageList.EXTRA_NETWORK_TEMPLATE, template)
+        }
+        return SubSettingLauncher(context).apply {
+            setDestination(BillingCycleSettings::class.java.name)
+            setArguments(args)
+            setTitleRes(R.string.billing_cycle)
+            setSourceMetricsCategory(SettingsEnums.PAGE_UNKNOWN)
+        }.toIntent()
+    }
+}
diff --git a/src/com/android/settings/datausage/BillingCyclePreferenceController.java b/src/com/android/settings/datausage/BillingCyclePreferenceController.java
index 73216ab..ff1f704 100644
--- a/src/com/android/settings/datausage/BillingCyclePreferenceController.java
+++ b/src/com/android/settings/datausage/BillingCyclePreferenceController.java
@@ -17,20 +17,12 @@
 package com.android.settings.datausage;
 
 import android.content.Context;
-import android.net.NetworkPolicyManager;
 import android.net.NetworkTemplate;
-import android.os.INetworkManagementService;
-import android.os.ServiceManager;
-import android.os.UserManager;
-import android.telephony.SubscriptionManager;
-import android.telephony.TelephonyManager;
 
 import androidx.preference.PreferenceScreen;
 
 import com.android.settings.core.BasePreferenceController;
-import com.android.settings.datausage.DataUsageUtils;
 import com.android.settings.datausage.lib.DataUsageLib;
-import com.android.settingslib.NetworkPolicyEditor;
 
 public class BillingCyclePreferenceController extends BasePreferenceController {
     private int mSubscriptionId;
@@ -48,18 +40,9 @@
         super.displayPreference(screen);
         BillingCyclePreference preference = screen.findPreference(getPreferenceKey());
 
-        TemplatePreference.NetworkServices services = new TemplatePreference.NetworkServices();
-        services.mNetworkService = INetworkManagementService.Stub.asInterface(
-                ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE));
-        services.mPolicyManager = mContext.getSystemService(NetworkPolicyManager.class);
-        services.mPolicyEditor = new NetworkPolicyEditor(services.mPolicyManager);
-        services.mTelephonyManager = mContext.getSystemService(TelephonyManager.class);
-        services.mSubscriptionManager = mContext.getSystemService(SubscriptionManager.class);
-        services.mUserManager = mContext.getSystemService(UserManager.class);
-
         NetworkTemplate template = DataUsageLib.getMobileTemplate(mContext, mSubscriptionId);
 
-        preference.setTemplate(template, mSubscriptionId, services);
+        preference.setTemplate(template, mSubscriptionId, null);
     }
 
     @Override
diff --git a/src/com/android/settings/datausage/lib/BillingCycleRepository.kt b/src/com/android/settings/datausage/lib/BillingCycleRepository.kt
new file mode 100644
index 0000000..779ae4a
--- /dev/null
+++ b/src/com/android/settings/datausage/lib/BillingCycleRepository.kt
@@ -0,0 +1,53 @@
+/*
+ * 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.datausage.lib
+
+import android.content.Context
+import android.os.INetworkManagementService
+import android.os.ServiceManager
+import android.telephony.TelephonyManager
+import android.util.Log
+import com.android.settingslib.spaprivileged.framework.common.userManager
+
+class BillingCycleRepository(
+    context: Context,
+    private val networkService: INetworkManagementService =
+        INetworkManagementService.Stub.asInterface(
+            ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE)
+        ),
+) {
+    private val userManager = context.userManager
+    private val telephonyManager = context.getSystemService(TelephonyManager::class.java)!!
+
+    fun isModifiable(subId: Int): Boolean =
+        isBandwidthControlEnabled() && userManager.isAdminUser && isDataEnabled(subId)
+
+    fun isBandwidthControlEnabled(): Boolean = try {
+        networkService.isBandwidthControlEnabled
+    } catch (e: Exception) {
+        Log.w(TAG, "problem talking with INetworkManagementService: ", e)
+        false
+    }
+
+    private fun isDataEnabled(subId: Int): Boolean =
+        telephonyManager.createForSubscriptionId(subId)
+            .isDataEnabledForReason(TelephonyManager.DATA_ENABLED_REASON_USER)
+
+    companion object {
+        private const val TAG = "BillingCycleRepository"
+    }
+}
diff --git a/tests/spa_unit/src/com/android/settings/datausage/BillingCyclePreferenceTest.kt b/tests/spa_unit/src/com/android/settings/datausage/BillingCyclePreferenceTest.kt
new file mode 100644
index 0000000..22b4a7e
--- /dev/null
+++ b/tests/spa_unit/src/com/android/settings/datausage/BillingCyclePreferenceTest.kt
@@ -0,0 +1,60 @@
+/*
+ * 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.datausage
+
+import android.content.Context
+import android.net.NetworkTemplate
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.settings.datausage.lib.BillingCycleRepository
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.kotlin.doReturn
+import org.mockito.kotlin.mock
+
+@RunWith(AndroidJUnit4::class)
+class BillingCyclePreferenceTest {
+
+    private val mockBillingCycleRepository = mock<BillingCycleRepository> {
+        on { isModifiable(SUB_ID) } doReturn false
+    }
+
+    private val context: Context = ApplicationProvider.getApplicationContext()
+
+    private val preference = BillingCyclePreference(context, null, mockBillingCycleRepository)
+
+    @Test
+    fun isEnabled_initialState() {
+        val enabled = preference.isEnabled
+
+        assertThat(enabled).isTrue()
+    }
+
+    @Test
+    fun isEnabled_afterSetTemplate_updated() {
+        preference.setTemplate(mock<NetworkTemplate>(), SUB_ID, null)
+
+        val enabled = preference.isEnabled
+
+        assertThat(enabled).isFalse()
+    }
+
+    private companion object {
+        const val SUB_ID = 1
+    }
+}
diff --git a/tests/spa_unit/src/com/android/settings/datausage/lib/BillingCycleRepositoryTest.kt b/tests/spa_unit/src/com/android/settings/datausage/lib/BillingCycleRepositoryTest.kt
new file mode 100644
index 0000000..deaaf2d
--- /dev/null
+++ b/tests/spa_unit/src/com/android/settings/datausage/lib/BillingCycleRepositoryTest.kt
@@ -0,0 +1,120 @@
+/*
+ * 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.datausage.lib
+
+import android.content.Context
+import android.os.INetworkManagementService
+import android.os.UserManager
+import android.telephony.TelephonyManager
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.settingslib.spaprivileged.framework.common.userManager
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.kotlin.doReturn
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.spy
+import org.mockito.kotlin.whenever
+
+@RunWith(AndroidJUnit4::class)
+class BillingCycleRepositoryTest {
+
+    private val mockNetworkManagementService = mock<INetworkManagementService> {
+        on { isBandwidthControlEnabled } doReturn true
+    }
+
+    private val mockUserManager = mock<UserManager> {
+        on { isAdminUser } doReturn true
+    }
+
+    private val mockTelephonyManager = mock<TelephonyManager> {
+        on { createForSubscriptionId(SUB_ID) } doReturn mock
+        on { isDataEnabledForReason(TelephonyManager.DATA_ENABLED_REASON_USER) } doReturn false
+    }
+
+    private val context: Context = spy(ApplicationProvider.getApplicationContext()) {
+        on { userManager } doReturn mockUserManager
+        on { getSystemService(TelephonyManager::class.java) } doReturn mockTelephonyManager
+    }
+
+    private val repository = BillingCycleRepository(context, mockNetworkManagementService)
+
+    @Test
+    fun isModifiable_bandwidthControlDisabled_returnFalse() {
+        whenever(mockNetworkManagementService.isBandwidthControlEnabled).thenReturn(false)
+
+        val modifiable = repository.isModifiable(SUB_ID)
+
+        assertThat(modifiable).isFalse()
+    }
+
+    @Test
+    fun isModifiable_notAdminUser_returnFalse() {
+        whenever(mockUserManager.isAdminUser).thenReturn(false)
+
+        val modifiable = repository.isModifiable(SUB_ID)
+
+        assertThat(modifiable).isFalse()
+    }
+
+    @Test
+    fun isModifiable_dataDisabled_returnFalse() {
+        whenever(
+            mockTelephonyManager.isDataEnabledForReason(TelephonyManager.DATA_ENABLED_REASON_USER)
+        ).thenReturn(false)
+
+        val modifiable = repository.isModifiable(SUB_ID)
+
+        assertThat(modifiable).isFalse()
+    }
+
+    @Test
+    fun isModifiable_meetAllRequirements_returnTrue() {
+        whenever(mockNetworkManagementService.isBandwidthControlEnabled).thenReturn(true)
+        whenever(mockUserManager.isAdminUser).thenReturn(true)
+        whenever(
+            mockTelephonyManager.isDataEnabledForReason(TelephonyManager.DATA_ENABLED_REASON_USER)
+        ).thenReturn(true)
+
+        val modifiable = repository.isModifiable(SUB_ID)
+
+        assertThat(modifiable).isTrue()
+    }
+
+    @Test
+    fun isBandwidthControlEnabled_bandwidthControlDisabled_returnFalse() {
+        whenever(mockNetworkManagementService.isBandwidthControlEnabled).thenReturn(false)
+
+        val enabled = repository.isBandwidthControlEnabled()
+
+        assertThat(enabled).isFalse()
+    }
+
+    @Test
+    fun isBandwidthControlEnabled_bandwidthControlEnabled_returnTrue() {
+        whenever(mockNetworkManagementService.isBandwidthControlEnabled).thenReturn(true)
+
+        val enabled = repository.isBandwidthControlEnabled()
+
+        assertThat(enabled).isTrue()
+    }
+
+    private companion object {
+        const val SUB_ID = 1
+    }
+}
diff --git a/tests/unit/src/com/android/settings/datausage/BillingCyclePreferenceTest.java b/tests/unit/src/com/android/settings/datausage/BillingCyclePreferenceTest.java
deleted file mode 100644
index f74768f..0000000
--- a/tests/unit/src/com/android/settings/datausage/BillingCyclePreferenceTest.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright (C) 2022 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.datausage;
-
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.verify;
-
-import android.content.Context;
-import android.os.INetworkManagementService;
-import android.os.RemoteException;
-import android.os.UserManager;
-import android.telephony.TelephonyManager;
-import androidx.test.core.app.ApplicationProvider;
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-@RunWith(AndroidJUnit4.class)
-public class BillingCyclePreferenceTest {
-
-    private Context mContext;
-    private BillingCyclePreference mPreference;
-    private TemplatePreference.NetworkServices mServices;
-    @Mock
-    private INetworkManagementService mNetManageSerice;
-    @Mock
-    private TelephonyManager mTelephonyManager;
-    @Mock
-    private UserManager mUserManager;
-
-    @Before
-    public void setUp() {
-        MockitoAnnotations.initMocks(this);
-        mContext = spy(ApplicationProvider.getApplicationContext());
-
-        mServices = new TemplatePreference.NetworkServices();
-        mServices.mNetworkService = mNetManageSerice;
-        mServices.mTelephonyManager = mTelephonyManager;
-        mServices.mUserManager = mUserManager;
-
-        doReturn(mTelephonyManager).when(mTelephonyManager)
-                .createForSubscriptionId(anyInt());
-
-        mPreference = spy(new BillingCyclePreference(mContext, null /* attrs */));
-        mPreference.setTemplate(null, 0, mServices);
-    }
-
-    @Test
-    public void testPreferenceUpdate_onMobileDataEnabledChange_accessDataEnabledApi() {
-        try {
-            doReturn(true).when(mNetManageSerice).isBandwidthControlEnabled();
-        } catch (RemoteException exception) {}
-        doReturn(true).when(mUserManager).isAdminUser();
-        mPreference.onMobileDataEnabledChange();
-
-        verify(mTelephonyManager)
-                .isDataEnabledForReason(TelephonyManager.DATA_ENABLED_REASON_USER);
-    }
-}
\ No newline at end of file