From ba1ec910ac0ccb2472d2e8af19ad2b233f23fa9c Mon Sep 17 00:00:00 2001 From: Chaohui Wang Date: Thu, 21 Sep 2023 12:23:53 +0800 Subject: [PATCH] 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 --- .../datausage/BillingCyclePreference.java | 107 ---------------- .../datausage/BillingCyclePreference.kt | 80 ++++++++++++ .../BillingCyclePreferenceController.java | 19 +-- .../datausage/lib/BillingCycleRepository.kt | 53 ++++++++ .../datausage/BillingCyclePreferenceTest.kt | 60 +++++++++ .../lib/BillingCycleRepositoryTest.kt | 120 ++++++++++++++++++ .../datausage/BillingCyclePreferenceTest.java | 78 ------------ 7 files changed, 314 insertions(+), 203 deletions(-) delete mode 100644 src/com/android/settings/datausage/BillingCyclePreference.java create mode 100644 src/com/android/settings/datausage/BillingCyclePreference.kt create mode 100644 src/com/android/settings/datausage/lib/BillingCycleRepository.kt create mode 100644 tests/spa_unit/src/com/android/settings/datausage/BillingCyclePreferenceTest.kt create mode 100644 tests/spa_unit/src/com/android/settings/datausage/lib/BillingCycleRepositoryTest.kt delete mode 100644 tests/unit/src/com/android/settings/datausage/BillingCyclePreferenceTest.java diff --git a/src/com/android/settings/datausage/BillingCyclePreference.java b/src/com/android/settings/datausage/BillingCyclePreference.java deleted file mode 100644 index 1bd2be8f078..00000000000 --- 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 00000000000..bdae4fab63c --- /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 73216ab72f4..ff1f7048130 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 @@ public class BillingCyclePreferenceController extends BasePreferenceController { 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 00000000000..779ae4a3a4b --- /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 00000000000..22b4a7ef17b --- /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 { + 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(), 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 00000000000..deaaf2dd1f0 --- /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 { + on { isBandwidthControlEnabled } doReturn true + } + + private val mockUserManager = mock { + on { isAdminUser } doReturn true + } + + private val mockTelephonyManager = mock { + 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 f74768fdda6..00000000000 --- 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