android:launchMode="singleTask">
</activity>
+ <activity android:name=".mobilenetwork.MobileSettingsActivity"
+ android:label="@string/network_settings_title"
+ android:theme="@style/Theme.Settings.Home"
+ android:launchMode="singleTask">
+ <!-- TODO(b/114749736): add intent filter here and disable the one in telephony -->
+ </activity>
+
<!-- Alias for launcher activity only, as this belongs to each profile. -->
<activity-alias android:name="Settings"
android:taskAffinity="com.android.settings.root"
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ 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.
+ -->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+ <Toolbar
+ android:id="@+id/action_bar"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:navigationContentDescription="@*android:string/action_bar_up_description"
+ android:theme="?android:attr/actionBarTheme"
+ style="?android:attr/actionBarStyle"/>
+
+ <FrameLayout
+ android:id="@+id/main_content"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"/>
+
+ <com.google.android.material.bottomnavigation.BottomNavigationView
+ android:id="@+id/bottom_nav"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_alignParentBottom="true"
+ android:layout_marginEnd="0dp"
+ android:layout_marginStart="0dp"
+ android:background="?android:attr/windowBackground"
+ app:itemIconTint="@color/bottom_navigation_colors"
+ app:itemTextColor="@color/bottom_navigation_colors"
+ app:menu="@menu/home_bottom_navigation"/>
+</LinearLayout>
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
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;
import com.android.settingslib.RestrictedSwitchPreference;
import com.android.settingslib.search.SearchIndexable;
-import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
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;
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
// 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<SubscriptionInfo> 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<SubscriptionInfo> 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:-");
}
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);
// Initialize mActiveSubInfo
int max = mSubscriptionManager.getActiveSubscriptionInfoCountMax();
- mActiveSubInfos = new ArrayList<SubscriptionInfo>(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();
}
}
@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);
if (mUm.hasUserRestriction(UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS)
//TODO(b/114749736): migrate telephony_disallowed_preference_screen.xml
} else {
initializeSubscriptions();
- updateCurrentTab(getActivity().getIntent());
}
}
}
private boolean hasActiveSubscriptions() {
- return mActiveSubInfos.size() > 0;
+ return mSubId != SubscriptionManager.INVALID_SUBSCRIPTION_ID;
}
private void updateBodyBasicFields(FragmentActivity activity, PreferenceScreen prefSet,
--- /dev/null
+/*
+ * 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<SubscriptionInfo> 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
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;
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(
--- /dev/null
+/*
+ * 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<SubscriptionInfo> 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);
+ }
+}