diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 94be61c9312..386c99ca51d 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -131,6 +131,13 @@ android:launchMode="singleTask"> + + + + + + + + + + + + + + diff --git a/src/com/android/settings/mobilenetwork/AdvancedOptionsPreference.java b/src/com/android/settings/mobilenetwork/AdvancedOptionsPreference.java index c13c3e22c0a..78392d684c8 100644 --- a/src/com/android/settings/mobilenetwork/AdvancedOptionsPreference.java +++ b/src/com/android/settings/mobilenetwork/AdvancedOptionsPreference.java @@ -33,14 +33,4 @@ public class AdvancedOptionsPreference extends Preference { public AdvancedOptionsPreference(Context context, AttributeSet attrs) { super(context, attrs); } - - @Override - public void onBindViewHolder(PreferenceViewHolder holder) { - super.onBindViewHolder(holder); - - setIcon(R.drawable.ic_expand_more); - setTitle(R.string.advanced_options_title); - TextView summary = (TextView) holder.findViewById(android.R.id.summary); - summary.setMaxLines(1); - } } \ No newline at end of file diff --git a/src/com/android/settings/mobilenetwork/MobileNetworkFragment.java b/src/com/android/settings/mobilenetwork/MobileNetworkFragment.java index 511cd032498..f93e352049c 100644 --- a/src/com/android/settings/mobilenetwork/MobileNetworkFragment.java +++ b/src/com/android/settings/mobilenetwork/MobileNetworkFragment.java @@ -46,11 +46,7 @@ import android.telephony.TelephonyManager; import android.telephony.euicc.EuiccManager; import android.text.TextUtils; import android.util.Log; -import android.view.LayoutInflater; import android.view.MenuItem; -import android.view.View; -import android.view.ViewGroup; -import android.widget.TabHost; import com.android.ims.ImsConfig; import com.android.ims.ImsManager; @@ -67,7 +63,6 @@ import com.android.settingslib.RestrictedLockUtilsInternal; import com.android.settingslib.RestrictedSwitchPreference; import com.android.settingslib.search.SearchIndexable; -import java.util.ArrayList; import java.util.Iterator; import java.util.List; @@ -174,9 +169,6 @@ public class MobileNetworkFragment extends DashboardFragment implements private boolean mOkClicked; private boolean mExpandAdvancedFields; - // We assume the the value returned by mTabHost.getCurrentTab() == slotId - private TabHost mTabHost; - //GsmUmts options and Cdma options GsmUmtsOptions mGsmUmtsOptions; CdmaOptions mCdmaOptions; @@ -226,13 +218,6 @@ public class MobileNetworkFragment extends DashboardFragment implements private final PhoneCallStateListener mPhoneStateListener = new PhoneCallStateListener(); - //TODO(b/114749736): figure out a way to update this fragment from intent - public void onIntentUpdate(Intent intent) { - if (!mUnavailable) { - updateCurrentTab(intent); - } - } - @Override public int getMetricsCategory() { //TODO(b/114749736): add metrics id for it @@ -356,78 +341,7 @@ public class MobileNetworkFragment extends DashboardFragment implements // Process preferences in activity only if its not destroyed return; } - int currentTab = 0; - if (DBG) log("initializeSubscriptions:+"); - - // Before updating the the active subscription list check - // if tab updating is needed as the list is changing. - List sil = mSubscriptionManager.getActiveSubscriptionInfoList(); - TabState state = isUpdateTabsNeeded(sil); - - // Update to the active subscription list - mActiveSubInfos.clear(); - if (sil != null) { - mActiveSubInfos.addAll(sil); - // If there is only 1 sim then currenTab should represent slot no. of the sim. - if (sil.size() == 1) { - currentTab = sil.get(0).getSimSlotIndex(); - } - } - - switch (state) { - case UPDATE: { - if (DBG) log("initializeSubscriptions: UPDATE"); - currentTab = mTabHost != null ? mTabHost.getCurrentTab() : 0; - - mTabHost = (TabHost) getActivity().findViewById(android.R.id.tabhost); - mTabHost.setup(); - - // Update the tabName. Since the mActiveSubInfos are in slot order - // we can iterate though the tabs and subscription info in one loop. But - // we need to handle the case where a slot may be empty. - - Iterator siIterator = mActiveSubInfos.listIterator(); - SubscriptionInfo si = siIterator.hasNext() ? siIterator.next() : null; - for (int simSlotIndex = 0; simSlotIndex < mActiveSubInfos.size(); - simSlotIndex++) { - String tabName; - if (si != null && si.getSimSlotIndex() == simSlotIndex) { - // Slot is not empty and we match - tabName = String.valueOf(si.getDisplayName()); - si = siIterator.hasNext() ? siIterator.next() : null; - } else { - // Slot is empty, set name to unknown - tabName = getResources().getString(R.string.unknown); - } - if (DBG) { - log("initializeSubscriptions:tab=" + simSlotIndex + " name=" + tabName); - } - - mTabHost.addTab(buildTabSpec(String.valueOf(simSlotIndex), tabName)); - } - - mTabHost.setOnTabChangedListener(mTabListener); - mTabHost.setCurrentTab(currentTab); - break; - } - case NO_TABS: { - if (DBG) log("initializeSubscriptions: NO_TABS"); - - if (mTabHost != null) { - mTabHost.clearAllTabs(); - mTabHost = null; - } - break; - } - case DO_NOTHING: { - if (DBG) log("initializeSubscriptions: DO_NOTHING"); - if (mTabHost != null) { - currentTab = mTabHost.getCurrentTab(); - } - break; - } - } - updatePhone(currentTab); + updatePhone(); updateBody(); if (DBG) log("initializeSubscriptions:-"); } @@ -465,60 +379,16 @@ public class MobileNetworkFragment extends DashboardFragment implements return state; } - private TabHost.OnTabChangeListener mTabListener = new TabHost.OnTabChangeListener() { - @Override - public void onTabChanged(String tabId) { - if (DBG) log("onTabChanged:"); - // The User has changed tab; update the body. - updatePhone(Integer.parseInt(tabId)); - updateBody(); - } - }; - - private void updatePhone(int slotId) { - final SubscriptionInfo sir = mSubscriptionManager - .getActiveSubscriptionInfoForSimSlotIndex(slotId); - - if (sir != null) { - mSubId = sir.getSubscriptionId(); - - Log.i(LOG_TAG, "updatePhone:- slotId=" + slotId + " sir=" + sir); - + private void updatePhone() { + if (mSubId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) { mImsMgr = ImsManager.getInstance(getContext(), SubscriptionManager.getPhoneId(mSubId)); mTelephonyManager = new TelephonyManager(getContext(), mSubId); - if (mImsMgr == null) { - log("updatePhone :: Could not get ImsManager instance!"); - } else if (DBG) { - log("updatePhone :: mImsMgr=" + mImsMgr); - } - } else { - // There is no active subscription in the given slot. - mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; } mPhoneStateListener.updateSubscriptionId(mSubId); } - private TabHost.TabContentFactory mEmptyTabContent = new TabHost.TabContentFactory() { - @Override - public View createTabContent(String tag) { - return new View(mTabHost.getContext()); - } - }; - - private TabHost.TabSpec buildTabSpec(String tag, String title) { - return mTabHost.newTabSpec(tag).setIndicator(title).setContent( - mEmptyTabContent); - } - - private void updateCurrentTab(Intent intent) { - int slotId = getSlotIdFromIntent(intent); - if (slotId >= 0 && mTabHost != null && mTabHost.getCurrentTab() != slotId) { - mTabHost.setCurrentTab(slotId); - } - } - @Override public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); @@ -591,23 +461,17 @@ public class MobileNetworkFragment extends DashboardFragment implements // Initialize mActiveSubInfo int max = mSubscriptionManager.getActiveSubscriptionInfoCountMax(); - mActiveSubInfos = new ArrayList(max); + mActiveSubInfos = mSubscriptionManager.getActiveSubscriptionInfoList(); + mSubId = getArguments().getInt(MobileSettingsActivity.KEY_SUBSCRIPTION_ID, + SubscriptionManager.INVALID_SUBSCRIPTION_ID); - int currentTab = mTabHost != null ? mTabHost.getCurrentTab() : 0; - updatePhone(currentTab); + updatePhone(); if (hasActiveSubscriptions()) { updateEnabledNetworksEntries(); } Log.i(LOG_TAG, "onCreate:-"); } - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { - return inflater.inflate(com.android.internal.R.layout.common_tab_settings, - container, false); - } - @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); @@ -617,7 +481,6 @@ public class MobileNetworkFragment extends DashboardFragment implements //TODO(b/114749736): migrate telephony_disallowed_preference_screen.xml } else { initializeSubscriptions(); - updateCurrentTab(getActivity().getIntent()); } } @@ -714,7 +577,7 @@ public class MobileNetworkFragment extends DashboardFragment implements } private boolean hasActiveSubscriptions() { - return mActiveSubInfos.size() > 0; + return mSubId != SubscriptionManager.INVALID_SUBSCRIPTION_ID; } private void updateBodyBasicFields(FragmentActivity activity, PreferenceScreen prefSet, diff --git a/src/com/android/settings/mobilenetwork/MobileSettingsActivity.java b/src/com/android/settings/mobilenetwork/MobileSettingsActivity.java new file mode 100644 index 00000000000..37a180cf3e8 --- /dev/null +++ b/src/com/android/settings/mobilenetwork/MobileSettingsActivity.java @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2018 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.mobilenetwork; + +import android.content.Intent; +import android.os.Bundle; +import android.telephony.SubscriptionInfo; +import android.telephony.SubscriptionManager; +import android.view.Menu; +import android.view.View; + +import com.android.internal.util.CollectionUtils; +import com.android.settings.R; +import com.android.settings.core.SettingsBaseActivity; + +import com.google.android.material.bottomnavigation.BottomNavigationView; + +import java.util.List; + +import androidx.annotation.VisibleForTesting; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentManager; +import androidx.fragment.app.FragmentTransaction; + +public class MobileSettingsActivity extends SettingsBaseActivity { + + @VisibleForTesting + static final String MOBILE_SETTINGS_TAG = "mobile_settings:"; + public static final String KEY_SUBSCRIPTION_ID = "key_subscription_id"; + + private SubscriptionManager mSubscriptionManager; + @VisibleForTesting + int mPrevSubscriptionId; + @VisibleForTesting + List mSubscriptionInfos; + + @Override + protected void onNewIntent(Intent intent) { + super.onNewIntent(intent); + //TODO(b/114749736): update fragment by new intent, or at least make sure this page shows + // current tab for sim card + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + mSubscriptionManager = getSystemService(SubscriptionManager.class); + mSubscriptionInfos = mSubscriptionManager.getActiveSubscriptionInfoList(); + mPrevSubscriptionId = CollectionUtils.isEmpty(mSubscriptionInfos) + ? SubscriptionManager.INVALID_SUBSCRIPTION_ID + : mSubscriptionInfos.get(0).getSubscriptionId(); + + setContentView(R.layout.mobile_settings_container); + + updateBottomNavigationView(); + + if (savedInstanceState == null) { + switchFragment(new MobileNetworkFragment(), mPrevSubscriptionId); + } + } + + @VisibleForTesting + void updateBottomNavigationView() { + final BottomNavigationView navigation = findViewById(R.id.bottom_nav); + + if (CollectionUtils.size(mSubscriptionInfos) <= 1) { + navigation.setVisibility(View.GONE); + } else { + final Menu menu = navigation.getMenu(); + menu.clear(); + for (int i = 0, size = mSubscriptionInfos.size(); i < size; i++) { + final SubscriptionInfo subscriptionInfo = mSubscriptionInfos.get(i); + menu.add(0, subscriptionInfo.getSubscriptionId(), i, + subscriptionInfo.getDisplayName()); + } + navigation.setOnNavigationItemSelectedListener(item -> { + switchFragment(new MobileNetworkFragment(), item.getItemId()); + mPrevSubscriptionId = item.getItemId(); + return true; + }); + + } + } + + @VisibleForTesting + void switchFragment(Fragment fragment, int subscriptionId) { + final FragmentManager fragmentManager = getSupportFragmentManager(); + final FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); + final Bundle bundle = new Bundle(); + bundle.putInt(KEY_SUBSCRIPTION_ID, subscriptionId); + + final Fragment hideFragment = fragmentManager.findFragmentByTag( + buildFragmentTag(mPrevSubscriptionId)); + if (hideFragment != null) { + fragmentTransaction.hide(hideFragment); + } + + Fragment showFragment = fragmentManager.findFragmentByTag(buildFragmentTag(subscriptionId)); + if (showFragment == null) { + fragment.setArguments(bundle); + fragmentTransaction.add(R.id.main_content, fragment, buildFragmentTag(subscriptionId)); + } else { + showFragment.setArguments(bundle); + fragmentTransaction.show(showFragment); + } + fragmentTransaction.commit(); + } + + private String buildFragmentTag(int subscriptionId) { + return MOBILE_SETTINGS_TAG + subscriptionId; + } +} \ No newline at end of file diff --git a/src/com/android/settings/network/MobileNetworkPreferenceController.java b/src/com/android/settings/network/MobileNetworkPreferenceController.java index 4230c670a09..c0e6e1c0d29 100644 --- a/src/com/android/settings/network/MobileNetworkPreferenceController.java +++ b/src/com/android/settings/network/MobileNetworkPreferenceController.java @@ -36,6 +36,7 @@ import androidx.preference.PreferenceScreen; import com.android.settings.core.FeatureFlags; import com.android.settings.core.PreferenceControllerMixin; +import com.android.settings.mobilenetwork.MobileSettingsActivity; import com.android.settingslib.RestrictedLockUtilsInternal; import com.android.settingslib.RestrictedPreference; import com.android.settingslib.Utils; @@ -146,7 +147,8 @@ public class MobileNetworkPreferenceController extends AbstractPreferenceControl public boolean handlePreferenceTreeClick(Preference preference) { if (KEY_MOBILE_NETWORK_SETTINGS.equals(preference.getKey())) { if (FeatureFlagUtils.isEnabled(mContext, FeatureFlags.MOBILE_NETWORK_V2)) { - //TODO(b/110260193): go to the mobile network page existed in settings + final Intent intent = new Intent(mContext, MobileSettingsActivity.class); + mContext.startActivity(intent); } else { final Intent intent = new Intent(Intent.ACTION_MAIN); intent.setComponent( diff --git a/tests/robotests/src/com/android/settings/mobilenetwork/MobileSettingsActivityTest.java b/tests/robotests/src/com/android/settings/mobilenetwork/MobileSettingsActivityTest.java new file mode 100644 index 00000000000..cb86d6f3d27 --- /dev/null +++ b/tests/robotests/src/com/android/settings/mobilenetwork/MobileSettingsActivityTest.java @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2018 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.mobilenetwork; + +import static com.android.settings.mobilenetwork.MobileSettingsActivity.MOBILE_SETTINGS_TAG; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; + +import android.content.Context; +import android.telephony.SubscriptionInfo; +import android.telephony.SubscriptionManager; +import android.view.Menu; +import android.view.View; + +import com.android.internal.view.menu.ContextMenuBuilder; +import com.android.settings.R; +import com.android.settings.testutils.SettingsRobolectricTestRunner; + +import com.google.android.material.bottomnavigation.BottomNavigationView; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.RuntimeEnvironment; + +import java.util.ArrayList; +import java.util.List; + +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentManager; +import androidx.fragment.app.FragmentTransaction; + +@RunWith(SettingsRobolectricTestRunner.class) +public class MobileSettingsActivityTest { + + private static final int CURRENT_SUB_ID = 3; + private static final int PREV_SUB_ID = 1; + + private Context mContext; + private MobileSettingsActivity mMobileSettingsActivity; + private List mSubscriptionInfos; + private Fragment mShowFragment; + private Fragment mHideFragment; + + @Mock + private SubscriptionManager mSubscriptionManager; + @Mock + private SubscriptionInfo mSubscriptionInfo; + @Mock + private FragmentManager mFragmentManager; + @Mock + private FragmentTransaction mFragmentTransaction; + @Mock + private BottomNavigationView mBottomNavigationView; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mContext = spy(RuntimeEnvironment.application); + + mMobileSettingsActivity = spy(new MobileSettingsActivity()); + mSubscriptionInfos = new ArrayList<>(); + mShowFragment = new Fragment(); + mHideFragment = new Fragment(); + mMobileSettingsActivity.mSubscriptionInfos = mSubscriptionInfos; + + doReturn(mSubscriptionManager).when(mMobileSettingsActivity).getSystemService( + SubscriptionManager.class); + doReturn(mBottomNavigationView).when(mMobileSettingsActivity).findViewById(R.id.bottom_nav); + doReturn(mFragmentManager).when(mMobileSettingsActivity).getSupportFragmentManager(); + doReturn(mFragmentTransaction).when(mFragmentManager).beginTransaction(); + doReturn(mHideFragment).when(mFragmentManager).findFragmentByTag( + MOBILE_SETTINGS_TAG + PREV_SUB_ID); + doReturn(mShowFragment).when(mFragmentManager).findFragmentByTag( + MOBILE_SETTINGS_TAG + CURRENT_SUB_ID); + } + + @Test + public void updateBottomNavigationView_oneSubscription_shouldBeGone() { + mSubscriptionInfos.add(mSubscriptionInfo); + doReturn(mSubscriptionInfos).when(mSubscriptionManager).getActiveSubscriptionInfoList(); + + mMobileSettingsActivity.updateBottomNavigationView(); + + verify(mBottomNavigationView).setVisibility(View.GONE); + } + + @Test + public void updateBottomNavigationView_twoSubscription_updateMenu() { + final Menu menu = new ContextMenuBuilder(mContext); + mSubscriptionInfos.add(mSubscriptionInfo); + mSubscriptionInfos.add(mSubscriptionInfo); + doReturn(mSubscriptionInfos).when(mSubscriptionManager).getActiveSubscriptionInfoList(); + doReturn(menu).when(mBottomNavigationView).getMenu(); + + mMobileSettingsActivity.updateBottomNavigationView(); + + assertThat(menu.size()).isEqualTo(2); + } + + @Test + public void switchFragment_hidePreviousFragment() { + mMobileSettingsActivity.mPrevSubscriptionId = PREV_SUB_ID; + + mMobileSettingsActivity.switchFragment(mShowFragment, CURRENT_SUB_ID); + + verify(mFragmentTransaction).hide(mHideFragment); + } + + @Test + public void switchFragment_fragmentExist_showItWithArguments() { + mMobileSettingsActivity.mPrevSubscriptionId = PREV_SUB_ID; + + mMobileSettingsActivity.switchFragment(mShowFragment, CURRENT_SUB_ID); + + assertThat(mShowFragment.getArguments().getInt( + MobileSettingsActivity.KEY_SUBSCRIPTION_ID)).isEqualTo(CURRENT_SUB_ID); + verify(mFragmentTransaction).show(mShowFragment); + } +}