diff --git a/res/xml/network_provider_settings.xml b/res/xml/network_provider_settings.xml index c0f2edd2c86..c374469d754 100644 --- a/res/xml/network_provider_settings.xml +++ b/res/xml/network_provider_settings.xml @@ -27,6 +27,12 @@ android:key="connected_access_point" android:layout="@layout/preference_category_no_label"/> + + diff --git a/src/com/android/settings/network/MultiNetworkHeaderController.java b/src/com/android/settings/network/MultiNetworkHeaderController.java index e99cbb6e067..1143546859e 100644 --- a/src/com/android/settings/network/MultiNetworkHeaderController.java +++ b/src/com/android/settings/network/MultiNetworkHeaderController.java @@ -27,9 +27,14 @@ import com.android.settings.core.BasePreferenceController; import com.android.settings.wifi.WifiConnectionPreferenceController; import com.android.settingslib.core.lifecycle.Lifecycle; -// This controls a header at the top of the Network & internet page that only appears when there -// are two or more active mobile subscriptions. It shows an overview of available network -// connections with an entry for wifi (if connected) and an entry for each subscription. +/** + * This controls a header at the top of the Network & internet page that only appears when there + * are two or more active mobile subscriptions. It shows an overview of available network + * connections with an entry for wifi (if connected) and an entry for each subscription. + * + * TODO(tomhsu) when provider model is completed, this class will be replaced + * by {@link NetworkMobileProviderController} + */ public class MultiNetworkHeaderController extends BasePreferenceController implements WifiConnectionPreferenceController.UpdateListener, SubscriptionsPreferenceController.UpdateListener { diff --git a/src/com/android/settings/network/NetworkMobileProviderController.java b/src/com/android/settings/network/NetworkMobileProviderController.java new file mode 100644 index 00000000000..4c292561976 --- /dev/null +++ b/src/com/android/settings/network/NetworkMobileProviderController.java @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2020 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.network; + +import android.content.Context; +import android.util.Log; + +import androidx.annotation.VisibleForTesting; +import androidx.preference.PreferenceCategory; +import androidx.preference.PreferenceScreen; + +import com.android.settings.core.BasePreferenceController; +import com.android.settingslib.core.lifecycle.Lifecycle; + +/** + * This controls mobile network display of the internet page that only appears when there + * are active mobile subscriptions. It shows an overview of available mobile network + * connections with an entry for each subscription. + * + * {@link NetworkMobileProviderController} is used to show subscription status on internet + * page for provider model. This original class can refer to {@link MultiNetworkHeaderController}, + * + */ +public class NetworkMobileProviderController extends BasePreferenceController implements + SubscriptionsPreferenceController.UpdateListener { + + private static final String TAG = NetworkMobileProviderController.class.getSimpleName(); + + public static final String PREF_KEY_PROVIDER_MOBILE_NETWORK = "provider_model_mobile_network"; + private static final int PREFERENCE_START_ORDER = 10; + + private PreferenceCategory mPreferenceCategory; + private PreferenceScreen mPreferenceScreen; + + private SubscriptionsPreferenceController mSubscriptionsController; + + private int mOriginalExpandedChildrenCount; + + public NetworkMobileProviderController(Context context, String key) { + super(context, key); + } + + /** + * Initialize NetworkMobileProviderController + * @param lifecycle Lifecycle of Settings + */ + public void init(Lifecycle lifecycle) { + mSubscriptionsController = createSubscriptionsController(lifecycle); + } + + @VisibleForTesting + SubscriptionsPreferenceController createSubscriptionsController(Lifecycle lifecycle) { + if (mSubscriptionsController == null) { + return new SubscriptionsPreferenceController( + mContext, + lifecycle, + this, + PREF_KEY_PROVIDER_MOBILE_NETWORK, + PREFERENCE_START_ORDER); + } + return mSubscriptionsController; + } + + @Override + public void displayPreference(PreferenceScreen screen) { + super.displayPreference(screen); + if (mSubscriptionsController == null) { + Log.e(TAG, "[displayPreference] SubscriptionsController is null."); + return; + } + mPreferenceScreen = screen; + mOriginalExpandedChildrenCount = mPreferenceScreen.getInitialExpandedChildrenCount(); + mPreferenceCategory = screen.findPreference(PREF_KEY_PROVIDER_MOBILE_NETWORK); + mPreferenceCategory.setVisible(isAvailable()); + // TODO(tomhsu) For the provider model, subscriptionsController shall do more + // implementation of preference type change and summary control. + mSubscriptionsController.displayPreference(screen); + } + + @Override + public int getAvailabilityStatus() { + if (mSubscriptionsController == null) { + return CONDITIONALLY_UNAVAILABLE; + } + return mSubscriptionsController.isAvailable() ? AVAILABLE : CONDITIONALLY_UNAVAILABLE; + } + + @Override + public void onChildrenUpdated() { + final boolean available = isAvailable(); + // TODO(b/129893781) we need a better way to express where the advanced collapsing starts + // for preference groups that have items dynamically added/removed in the top expanded + // section. + if (mOriginalExpandedChildrenCount != Integer.MAX_VALUE) { + if (available) { + mPreferenceScreen.setInitialExpandedChildrenCount( + mOriginalExpandedChildrenCount + mPreferenceCategory.getPreferenceCount()); + } else { + mPreferenceScreen.setInitialExpandedChildrenCount(mOriginalExpandedChildrenCount); + } + } + mPreferenceCategory.setVisible(available); + } +} diff --git a/src/com/android/settings/network/NetworkProviderSettings.java b/src/com/android/settings/network/NetworkProviderSettings.java index df62190b7ee..90e3ac43fd8 100644 --- a/src/com/android/settings/network/NetworkProviderSettings.java +++ b/src/com/android/settings/network/NetworkProviderSettings.java @@ -207,6 +207,12 @@ public class NetworkProviderSettings extends RestrictedSettingsFragment DataUsagePreference mDataUsagePreference; private LinkablePreference mStatusMessagePreference; + /** + * Mobile networks list for provider model + */ + private static final String PREF_KEY_PROVIDER_MOBILE_NETWORK = "provider_model_mobile_network"; + private NetworkMobileProviderController mNetworkMobileProviderController; + /** * Tracks whether the user initiated a connection via clicking in order to autoscroll to the * network once connected. @@ -255,6 +261,16 @@ public class NetworkProviderSettings extends RestrictedSettingsFragment mDataUsagePreference.setTemplate(NetworkTemplate.buildTemplateWifiWildcard(), 0 /*subId*/, null /*service*/); + addNetworkMobileProviderController(); + } + + private void addNetworkMobileProviderController() { + if (mNetworkMobileProviderController == null) { + mNetworkMobileProviderController = new NetworkMobileProviderController( + getContext(), PREF_KEY_PROVIDER_MOBILE_NETWORK); + } + mNetworkMobileProviderController.init(getSettingsLifecycle()); + mNetworkMobileProviderController.displayPreference(getPreferenceScreen()); } @Override @@ -340,6 +356,12 @@ public class NetworkProviderSettings extends RestrictedSettingsFragment } } + @Override + public void onAttach(Context context) { + super.onAttach(context); + + } + @Override public void onDestroyView() { mWorkerThread.quit(); diff --git a/src/com/android/settings/network/SubscriptionsPreferenceController.java b/src/com/android/settings/network/SubscriptionsPreferenceController.java index 53d6c300b81..864078cf671 100644 --- a/src/com/android/settings/network/SubscriptionsPreferenceController.java +++ b/src/com/android/settings/network/SubscriptionsPreferenceController.java @@ -41,6 +41,7 @@ import androidx.preference.PreferenceGroup; import androidx.preference.PreferenceScreen; import com.android.settings.R; +import com.android.settings.Utils; import com.android.settings.network.telephony.DataConnectivityListener; import com.android.settings.network.telephony.MobileNetworkActivity; import com.android.settings.network.telephony.MobileNetworkUtils; @@ -77,7 +78,6 @@ public class SubscriptionsPreferenceController extends AbstractPreferenceControl // Map of subscription id to Preference private Map mSubscriptionPreferences; private int mStartOrder; - /** * This interface lets a parent of this class know that some change happened - this could * either be because overall availability changed, or because we've added/removed/updated some @@ -291,7 +291,7 @@ public class SubscriptionsPreferenceController extends AbstractPreferenceControl // subscriptions with same group UUID. .filter(subInfo -> isSubscriptionCanBeDisplayed(mContext, subInfo.getSubscriptionId())) - .count() >= 2; + .count() >= (Utils.isProviderModelEnabled(mContext) ? 1 : 2); } @Override diff --git a/tests/unit/src/com/android/settings/network/NetworkMobileProviderControllerTest.java b/tests/unit/src/com/android/settings/network/NetworkMobileProviderControllerTest.java new file mode 100644 index 00000000000..31c68da1307 --- /dev/null +++ b/tests/unit/src/com/android/settings/network/NetworkMobileProviderControllerTest.java @@ -0,0 +1,180 @@ +/* + * Copyright (C) 2020 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.network; + +import static com.android.settings.core.BasePreferenceController.AVAILABLE; +import static com.android.settings.core.BasePreferenceController.CONDITIONALLY_UNAVAILABLE; +import static com.android.settings.network.NetworkMobileProviderController.PREF_KEY_PROVIDER_MOBILE_NETWORK; + +import static com.google.common.truth.Truth.assertThat; + +import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertFalse; +import static junit.framework.Assert.assertTrue; + +import static org.mockito.Mockito.when; + +import android.content.Context; +import android.os.Looper; + +import androidx.preference.PreferenceCategory; +import androidx.preference.PreferenceManager; +import androidx.preference.PreferenceScreen; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; + +import com.android.settingslib.core.lifecycle.Lifecycle; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +/** + * Unit test for NetworkMobileProviderController. + * + * {@link NetworkMobileProviderController} is used to show subscription status on internet page for + * provider model. This original class can refer to {@link MultiNetworkHeaderController}, and + * NetworkMobileProviderControllerTest can also refer to {@link MultiNetworkHeaderControllerTest}. + */ +@RunWith(AndroidJUnit4.class) +public class NetworkMobileProviderControllerTest { + + private static final int EXPANDED_CHILDREN_COUNT = 3; + + @Mock + private Lifecycle mLifecycle; + @Mock + private PreferenceCategory mPreferenceCategory; + @Mock + private SubscriptionsPreferenceController mSubscriptionsController; + + private Context mContext; + private PreferenceManager mPreferenceManager; + private PreferenceScreen mPreferenceScreen; + private NetworkMobileProviderController mNetworkMobileProviderController; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + if (Looper.myLooper() == null) { + Looper.prepare(); + } + + when(mPreferenceCategory.getKey()).thenReturn(PREF_KEY_PROVIDER_MOBILE_NETWORK); + when(mPreferenceCategory.getPreferenceCount()).thenReturn(3); + + mContext = ApplicationProvider.getApplicationContext(); + mNetworkMobileProviderController = + new NetworkMobileProviderController(mContext, PREF_KEY_PROVIDER_MOBILE_NETWORK) { + @Override + SubscriptionsPreferenceController createSubscriptionsController( + Lifecycle lifecycle) { + return mSubscriptionsController; + } + }; + + mPreferenceManager = new PreferenceManager(mContext); + mPreferenceScreen = mPreferenceManager.createPreferenceScreen(mContext); + mPreferenceScreen.setInitialExpandedChildrenCount(EXPANDED_CHILDREN_COUNT); + mPreferenceScreen.addPreference(mPreferenceCategory); + } + + @Test + public void testDisplayPreference_subscriptionsControllerAvailable() { + when(mSubscriptionsController.isAvailable()).thenReturn(true); + setupNetworkMobileProviderController(); + + assertTrue(mPreferenceCategory.isVisible()); + } + + @Test + public void testDisplayPreference_subscriptionsControllerUnAvailable() { + when(mSubscriptionsController.isAvailable()).thenReturn(false); + setupNetworkMobileProviderController(); + + assertFalse(mPreferenceCategory.isVisible()); + } + + @Test + public void testGetAvailabilityStatus_subscriptionsControllerIsNull() { + when(mSubscriptionsController.isAvailable()).thenReturn(false); + mNetworkMobileProviderController = new NetworkMobileProviderController(mContext, + PREF_KEY_PROVIDER_MOBILE_NETWORK) { + @Override + SubscriptionsPreferenceController createSubscriptionsController(Lifecycle lifecycle) { + return null; + } + }; + setupNetworkMobileProviderController(); + + final int result = mNetworkMobileProviderController.getAvailabilityStatus(); + + assertEquals(result, CONDITIONALLY_UNAVAILABLE); + } + + @Test + public void testGetAvailabilityStatus_subscriptionsControllerAvailable() { + when(mSubscriptionsController.isAvailable()).thenReturn(true); + setupNetworkMobileProviderController(); + + final int result = mNetworkMobileProviderController.getAvailabilityStatus(); + + assertEquals(result, AVAILABLE); + } + + @Test + public void testOnChildUpdated_subscriptionsControllerAvailable_categoryIsVisible() { + when(mSubscriptionsController.isAvailable()).thenReturn(true); + setupNetworkMobileProviderController(); + + mNetworkMobileProviderController.onChildrenUpdated(); + + assertTrue(mPreferenceCategory.isVisible()); + assertThat(mPreferenceScreen.getInitialExpandedChildrenCount()).isEqualTo( + EXPANDED_CHILDREN_COUNT + mPreferenceCategory.getPreferenceCount()); + } + + @Test + public void testOnChildUpdated_subscriptionsControllerUnavailable_categoryIsInvisible() { + when(mSubscriptionsController.isAvailable()).thenReturn(false); + setupNetworkMobileProviderController(); + + mNetworkMobileProviderController.onChildrenUpdated(); + + assertFalse(mPreferenceCategory.isVisible()); + assertThat(mPreferenceScreen.getInitialExpandedChildrenCount()).isEqualTo( + EXPANDED_CHILDREN_COUNT); + } + + @Test + public void testOnChildUpdated_noExpandedChildCountAndAvailable_doesNotSetExpandedCount() { + when(mSubscriptionsController.isAvailable()).thenReturn(true); + mPreferenceScreen.setInitialExpandedChildrenCount(Integer.MAX_VALUE); + setupNetworkMobileProviderController(); + + mNetworkMobileProviderController.onChildrenUpdated(); + + assertEquals(mPreferenceScreen.getInitialExpandedChildrenCount(), Integer.MAX_VALUE); + } + + private void setupNetworkMobileProviderController() { + mNetworkMobileProviderController.init(mLifecycle); + mNetworkMobileProviderController.displayPreference(mPreferenceScreen); + } +}