Merge "Fix restriction to configure Calls & SMS" into main
This commit is contained in:
@@ -1,29 +0,0 @@
|
|||||||
<!--
|
|
||||||
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.
|
|
||||||
-->
|
|
||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:width="24dp"
|
|
||||||
android:height="24dp"
|
|
||||||
android:viewportWidth="24"
|
|
||||||
android:viewportHeight="24"
|
|
||||||
android:tint="?android:attr/colorControlNormal"
|
|
||||||
>
|
|
||||||
|
|
||||||
<path
|
|
||||||
android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#FF000000"
|
|
||||||
android:pathData="M20.17,14.85l-3.26-0.65c-0.33-0.07-0.67,0.04-0.9,0.27l-2.62,2.62c-2.75-1.49-5.01-3.75-6.5-6.5l2.62-2.62 c0.24-0.24,0.34-0.58,0.27-0.9L9.13,3.82c-0.09-0.47-0.5-0.8-0.98-0.8H4c-0.56,0-1.03,0.47-1,1.03c0.17,2.91,1.04,5.63,2.43,8.01 c1.57,2.69,3.81,4.93,6.5,6.5c2.38,1.39,5.1,2.26,8.01,2.43c0.56,0.03,1.03-0.44,1.03-1v-4.15C20.97,15.36,20.64,14.95,20.17,14.85 L20.17,14.85z M12,3v10l3-3h6V3H12z M19,8h-5V5h5V8z" />
|
|
||||||
</vector>
|
|
@@ -31,16 +31,11 @@
|
|||||||
settings:keywords="@string/keywords_internet"
|
settings:keywords="@string/keywords_internet"
|
||||||
settings:useAdminDisabledSummary="true" />
|
settings:useAdminDisabledSummary="true" />
|
||||||
|
|
||||||
<com.android.settingslib.RestrictedPreference
|
<com.android.settings.spa.preference.ComposePreference
|
||||||
android:key="calls_and_sms"
|
android:key="calls_and_sms"
|
||||||
android:title="@string/calls_and_sms"
|
android:title="@string/calls_and_sms"
|
||||||
android:icon="@drawable/ic_calls_sms"
|
|
||||||
android:order="-20"
|
android:order="-20"
|
||||||
android:summary="@string/summary_placeholder"
|
settings:controller="com.android.settings.network.NetworkProviderCallsSmsController" />
|
||||||
settings:isPreferenceVisible="@bool/config_show_sim_info"
|
|
||||||
settings:allowDividerBelow="true"
|
|
||||||
settings:keywords="@string/calls_and_sms"
|
|
||||||
settings:useAdminDisabledSummary="true" />
|
|
||||||
|
|
||||||
<com.android.settingslib.RestrictedPreference
|
<com.android.settingslib.RestrictedPreference
|
||||||
android:key="mobile_network_list"
|
android:key="mobile_network_list"
|
||||||
|
@@ -22,7 +22,6 @@ import android.app.settings.SettingsEnums;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.provider.SearchIndexableResource;
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import androidx.appcompat.app.AlertDialog;
|
import androidx.appcompat.app.AlertDialog;
|
||||||
@@ -31,19 +30,16 @@ import androidx.lifecycle.LifecycleOwner;
|
|||||||
|
|
||||||
import com.android.settings.R;
|
import com.android.settings.R;
|
||||||
import com.android.settings.SettingsDumpService;
|
import com.android.settings.SettingsDumpService;
|
||||||
import com.android.settings.Utils;
|
|
||||||
import com.android.settings.core.OnActivityResultListener;
|
import com.android.settings.core.OnActivityResultListener;
|
||||||
import com.android.settings.dashboard.DashboardFragment;
|
import com.android.settings.dashboard.DashboardFragment;
|
||||||
import com.android.settings.network.MobilePlanPreferenceController.MobilePlanPreferenceHost;
|
import com.android.settings.network.MobilePlanPreferenceController.MobilePlanPreferenceHost;
|
||||||
import com.android.settings.search.BaseSearchIndexProvider;
|
import com.android.settings.search.BaseSearchIndexProvider;
|
||||||
import com.android.settings.wifi.WifiPrimarySwitchPreferenceController;
|
|
||||||
import com.android.settingslib.core.AbstractPreferenceController;
|
import com.android.settingslib.core.AbstractPreferenceController;
|
||||||
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
|
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
|
||||||
import com.android.settingslib.core.lifecycle.Lifecycle;
|
import com.android.settingslib.core.lifecycle.Lifecycle;
|
||||||
import com.android.settingslib.search.SearchIndexable;
|
import com.android.settingslib.search.SearchIndexable;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@SearchIndexable
|
@SearchIndexable
|
||||||
@@ -122,7 +118,6 @@ public class NetworkDashboardFragment extends DashboardFragment implements
|
|||||||
controllers.add(internetPreferenceController);
|
controllers.add(internetPreferenceController);
|
||||||
}
|
}
|
||||||
controllers.add(privateDnsPreferenceController);
|
controllers.add(privateDnsPreferenceController);
|
||||||
controllers.add(new NetworkProviderCallsSmsController(context, lifecycle, lifecycleOwner));
|
|
||||||
|
|
||||||
// Start SettingsDumpService after the MobileNetworkRepository is created.
|
// Start SettingsDumpService after the MobileNetworkRepository is created.
|
||||||
Intent intent = new Intent(context, SettingsDumpService.class);
|
Intent intent = new Intent(context, SettingsDumpService.class);
|
||||||
|
@@ -1,258 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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 androidx.lifecycle.Lifecycle.Event;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.os.UserManager;
|
|
||||||
import android.telephony.ServiceState;
|
|
||||||
import android.telephony.SubscriptionManager;
|
|
||||||
import android.telephony.TelephonyManager;
|
|
||||||
import android.util.Log;
|
|
||||||
import android.view.View;
|
|
||||||
|
|
||||||
import androidx.annotation.VisibleForTesting;
|
|
||||||
import androidx.lifecycle.LifecycleObserver;
|
|
||||||
import androidx.lifecycle.LifecycleOwner;
|
|
||||||
import androidx.lifecycle.OnLifecycleEvent;
|
|
||||||
import androidx.preference.Preference;
|
|
||||||
import androidx.preference.PreferenceScreen;
|
|
||||||
|
|
||||||
import com.android.settings.R;
|
|
||||||
import com.android.settingslib.RestrictedPreference;
|
|
||||||
import com.android.settingslib.Utils;
|
|
||||||
import com.android.settingslib.core.AbstractPreferenceController;
|
|
||||||
import com.android.settingslib.core.lifecycle.Lifecycle;
|
|
||||||
import com.android.settingslib.mobile.dataservice.SubscriptionInfoEntity;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class NetworkProviderCallsSmsController extends AbstractPreferenceController implements
|
|
||||||
LifecycleObserver, MobileNetworkRepository.MobileNetworkCallback,
|
|
||||||
DefaultSubscriptionReceiver.DefaultSubscriptionListener {
|
|
||||||
|
|
||||||
private static final String TAG = "NetworkProviderCallsSmsController";
|
|
||||||
private static final String KEY = "calls_and_sms";
|
|
||||||
private static final String RTL_MARK = "\u200F";
|
|
||||||
|
|
||||||
private UserManager mUserManager;
|
|
||||||
private TelephonyManager mTelephonyManager;
|
|
||||||
private RestrictedPreference mPreference;
|
|
||||||
private boolean mIsRtlMode;
|
|
||||||
private LifecycleOwner mLifecycleOwner;
|
|
||||||
private MobileNetworkRepository mMobileNetworkRepository;
|
|
||||||
private List<SubscriptionInfoEntity> mSubInfoEntityList;
|
|
||||||
private int mDefaultVoiceSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
|
|
||||||
private int mDefaultSmsSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
|
|
||||||
private DefaultSubscriptionReceiver mDataSubscriptionChangedReceiver;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The summary text and click behavior of the "Calls & SMS" item on the
|
|
||||||
* Network & internet page.
|
|
||||||
*/
|
|
||||||
public NetworkProviderCallsSmsController(Context context, Lifecycle lifecycle,
|
|
||||||
LifecycleOwner lifecycleOwner) {
|
|
||||||
super(context);
|
|
||||||
|
|
||||||
mUserManager = context.getSystemService(UserManager.class);
|
|
||||||
mTelephonyManager = mContext.getSystemService(TelephonyManager.class);
|
|
||||||
mIsRtlMode = context.getResources().getConfiguration().getLayoutDirection()
|
|
||||||
== View.LAYOUT_DIRECTION_RTL;
|
|
||||||
mLifecycleOwner = lifecycleOwner;
|
|
||||||
mMobileNetworkRepository = MobileNetworkRepository.getInstance(context);
|
|
||||||
mDataSubscriptionChangedReceiver = new DefaultSubscriptionReceiver(context, this);
|
|
||||||
if (lifecycle != null) {
|
|
||||||
lifecycle.addObserver(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@OnLifecycleEvent(Event.ON_RESUME)
|
|
||||||
public void onResume() {
|
|
||||||
mMobileNetworkRepository.addRegister(mLifecycleOwner, this,
|
|
||||||
SubscriptionManager.INVALID_SUBSCRIPTION_ID);
|
|
||||||
mMobileNetworkRepository.updateEntity();
|
|
||||||
mDataSubscriptionChangedReceiver.registerReceiver();
|
|
||||||
mDefaultVoiceSubId = SubscriptionManager.getDefaultVoiceSubscriptionId();
|
|
||||||
mDefaultSmsSubId = SubscriptionManager.getDefaultSmsSubscriptionId();
|
|
||||||
}
|
|
||||||
|
|
||||||
@OnLifecycleEvent(Event.ON_PAUSE)
|
|
||||||
public void onPause() {
|
|
||||||
mMobileNetworkRepository.removeRegister(this);
|
|
||||||
mDataSubscriptionChangedReceiver.unRegisterReceiver();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void displayPreference(PreferenceScreen screen) {
|
|
||||||
super.displayPreference(screen);
|
|
||||||
mPreference = screen.findPreference(getPreferenceKey());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public CharSequence getSummary() {
|
|
||||||
List<SubscriptionInfoEntity> list = getSubscriptionInfoList();
|
|
||||||
if (list == null || list.isEmpty()) {
|
|
||||||
return setSummaryResId(R.string.calls_sms_no_sim);
|
|
||||||
} else {
|
|
||||||
final StringBuilder summary = new StringBuilder();
|
|
||||||
SubscriptionInfoEntity[] entityArray = list.toArray(
|
|
||||||
new SubscriptionInfoEntity[0]);
|
|
||||||
for (SubscriptionInfoEntity subInfo : entityArray) {
|
|
||||||
int subsSize = list.size();
|
|
||||||
int subId = Integer.parseInt(subInfo.subId);
|
|
||||||
final CharSequence displayName = subInfo.uniqueName;
|
|
||||||
|
|
||||||
// Set displayName as summary if there is only one valid SIM.
|
|
||||||
if (subsSize == 1
|
|
||||||
&& list.get(0).isValidSubscription
|
|
||||||
&& isInService(subId)) {
|
|
||||||
return displayName;
|
|
||||||
}
|
|
||||||
|
|
||||||
CharSequence status = getPreferredStatus(subInfo, subsSize, subId);
|
|
||||||
if (status.toString().isEmpty()) {
|
|
||||||
// If there are 2 or more SIMs and one of these has no preferred status,
|
|
||||||
// set only its displayName as summary.
|
|
||||||
summary.append(displayName);
|
|
||||||
} else {
|
|
||||||
summary.append(displayName)
|
|
||||||
.append(" (")
|
|
||||||
.append(status)
|
|
||||||
.append(")");
|
|
||||||
}
|
|
||||||
// Do not add ", " for the last subscription.
|
|
||||||
if (list.size() > 0 && !subInfo.equals(list.get(list.size() - 1))) {
|
|
||||||
summary.append(", ");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mIsRtlMode) {
|
|
||||||
summary.insert(0, RTL_MARK).insert(summary.length(), RTL_MARK);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return summary;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@VisibleForTesting
|
|
||||||
protected CharSequence getPreferredStatus(SubscriptionInfoEntity subInfo, int subsSize,
|
|
||||||
int subId) {
|
|
||||||
String status = "";
|
|
||||||
boolean isCallPreferred = subInfo.getSubId() == getDefaultVoiceSubscriptionId();
|
|
||||||
boolean isSmsPreferred = subInfo.getSubId() == getDefaultSmsSubscriptionId();
|
|
||||||
|
|
||||||
if (!subInfo.isValidSubscription || !isInService(subId)) {
|
|
||||||
status = setSummaryResId(subsSize > 1 ? R.string.calls_sms_unavailable :
|
|
||||||
R.string.calls_sms_temp_unavailable);
|
|
||||||
} else {
|
|
||||||
if (isCallPreferred && isSmsPreferred) {
|
|
||||||
status = setSummaryResId(R.string.calls_sms_preferred);
|
|
||||||
} else if (isCallPreferred) {
|
|
||||||
status = setSummaryResId(R.string.calls_sms_calls_preferred);
|
|
||||||
} else if (isSmsPreferred) {
|
|
||||||
status = setSummaryResId(R.string.calls_sms_sms_preferred);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String setSummaryResId(int resId) {
|
|
||||||
return mContext.getResources().getString(resId);
|
|
||||||
}
|
|
||||||
|
|
||||||
@VisibleForTesting
|
|
||||||
protected List<SubscriptionInfoEntity> getSubscriptionInfoList() {
|
|
||||||
return mSubInfoEntityList;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void update() {
|
|
||||||
if (mPreference == null || mPreference.isDisabledByAdmin()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
refreshSummary(mPreference);
|
|
||||||
mPreference.setOnPreferenceClickListener(null);
|
|
||||||
mPreference.setFragment(null);
|
|
||||||
|
|
||||||
if (mSubInfoEntityList == null || mSubInfoEntityList.isEmpty()) {
|
|
||||||
mPreference.setEnabled(false);
|
|
||||||
} else {
|
|
||||||
mPreference.setEnabled(true);
|
|
||||||
mPreference.setFragment(NetworkProviderCallsSmsFragment.class.getCanonicalName());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isAvailable() {
|
|
||||||
return SubscriptionUtil.isSimHardwareVisible(mContext) &&
|
|
||||||
mUserManager.isAdminUser();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getPreferenceKey() {
|
|
||||||
return KEY;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onAirplaneModeChanged(boolean airplaneModeEnabled) {
|
|
||||||
update();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void updateState(Preference preference) {
|
|
||||||
super.updateState(preference);
|
|
||||||
if (preference == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
refreshSummary(mPreference);
|
|
||||||
update();
|
|
||||||
}
|
|
||||||
|
|
||||||
@VisibleForTesting
|
|
||||||
protected boolean isInService(int subId) {
|
|
||||||
ServiceState serviceState =
|
|
||||||
mTelephonyManager.createForSubscriptionId(subId).getServiceState();
|
|
||||||
return Utils.isInService(serviceState);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onActiveSubInfoChanged(List<SubscriptionInfoEntity> activeSubInfoList) {
|
|
||||||
mSubInfoEntityList = activeSubInfoList;
|
|
||||||
update();
|
|
||||||
}
|
|
||||||
|
|
||||||
@VisibleForTesting
|
|
||||||
protected int getDefaultVoiceSubscriptionId() {
|
|
||||||
return mDefaultVoiceSubId;
|
|
||||||
}
|
|
||||||
|
|
||||||
@VisibleForTesting
|
|
||||||
protected int getDefaultSmsSubscriptionId() {
|
|
||||||
return mDefaultSmsSubId;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onDefaultVoiceChanged(int defaultVoiceSubId) {
|
|
||||||
mDefaultVoiceSubId = defaultVoiceSubId;
|
|
||||||
update();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onDefaultSmsChanged(int defaultSmsSubId) {
|
|
||||||
mDefaultSmsSubId = defaultSmsSubId;
|
|
||||||
update();
|
|
||||||
}
|
|
||||||
}
|
|
@@ -0,0 +1,196 @@
|
|||||||
|
/*
|
||||||
|
* 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.network
|
||||||
|
|
||||||
|
import android.app.settings.SettingsEnums
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.IntentFilter
|
||||||
|
import android.os.UserManager
|
||||||
|
import android.telephony.SubscriptionInfo
|
||||||
|
import android.telephony.SubscriptionManager
|
||||||
|
import android.telephony.TelephonyManager
|
||||||
|
import androidx.annotation.VisibleForTesting
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.outlined.PermPhoneMsg
|
||||||
|
import androidx.compose.material3.HorizontalDivider
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||||
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
|
import com.android.settings.R
|
||||||
|
import com.android.settings.core.SubSettingLauncher
|
||||||
|
import com.android.settings.spa.preference.ComposePreferenceController
|
||||||
|
import com.android.settingslib.Utils
|
||||||
|
import com.android.settingslib.spa.widget.preference.PreferenceModel
|
||||||
|
import com.android.settingslib.spa.widget.ui.SettingsIcon
|
||||||
|
import com.android.settingslib.spaprivileged.framework.common.broadcastReceiverFlow
|
||||||
|
import com.android.settingslib.spaprivileged.framework.common.userManager
|
||||||
|
import com.android.settingslib.spaprivileged.framework.compose.placeholder
|
||||||
|
import com.android.settingslib.spaprivileged.model.enterprise.Restrictions
|
||||||
|
import com.android.settingslib.spaprivileged.template.preference.RestrictedPreference
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import kotlinx.coroutines.flow.combine
|
||||||
|
import kotlinx.coroutines.flow.conflate
|
||||||
|
import kotlinx.coroutines.flow.flowOf
|
||||||
|
import kotlinx.coroutines.flow.flowOn
|
||||||
|
import kotlinx.coroutines.flow.map
|
||||||
|
import kotlinx.coroutines.flow.merge
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The summary text and click behavior of the "Calls & SMS" item on the Network & internet page.
|
||||||
|
*/
|
||||||
|
open class NetworkProviderCallsSmsController @JvmOverloads constructor(
|
||||||
|
context: Context,
|
||||||
|
preferenceKey: String,
|
||||||
|
private val getDisplayName: (SubscriptionInfo) -> CharSequence = { subInfo ->
|
||||||
|
SubscriptionUtil.getUniqueSubscriptionDisplayName(subInfo, context)
|
||||||
|
},
|
||||||
|
private val isInService: (Int) -> Boolean = IsInServiceImpl(context)::isInService,
|
||||||
|
) : ComposePreferenceController(context, preferenceKey) {
|
||||||
|
|
||||||
|
override fun getAvailabilityStatus() = when {
|
||||||
|
!SubscriptionUtil.isSimHardwareVisible(mContext) -> UNSUPPORTED_ON_DEVICE
|
||||||
|
!mContext.userManager.isAdminUser -> DISABLED_FOR_USER
|
||||||
|
else -> AVAILABLE
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
override fun Content() {
|
||||||
|
Column {
|
||||||
|
CallsAndSms()
|
||||||
|
HorizontalDivider()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun CallsAndSms() {
|
||||||
|
val viewModel: SubscriptionInfoListViewModel = viewModel()
|
||||||
|
val subscriptionInfos by viewModel.subscriptionInfoListFlow.collectAsStateWithLifecycle()
|
||||||
|
val summary by remember { summaryFlow(viewModel.subscriptionInfoListFlow) }
|
||||||
|
.collectAsStateWithLifecycle(initialValue = placeholder())
|
||||||
|
RestrictedPreference(
|
||||||
|
model = object : PreferenceModel {
|
||||||
|
override val title = stringResource(R.string.calls_and_sms)
|
||||||
|
override val icon = @Composable { SettingsIcon(Icons.Outlined.PermPhoneMsg) }
|
||||||
|
override val summary = { summary }
|
||||||
|
override val enabled = { subscriptionInfos.isNotEmpty() }
|
||||||
|
override val onClick = {
|
||||||
|
SubSettingLauncher(mContext).apply {
|
||||||
|
setDestination(NetworkProviderCallsSmsFragment::class.qualifiedName)
|
||||||
|
setSourceMetricsCategory(SettingsEnums.SETTINGS_NETWORK_CATEGORY)
|
||||||
|
}.launch()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
restrictions = Restrictions(keys = listOf(UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS)),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun summaryFlow(subscriptionInfoListFlow: Flow<List<SubscriptionInfo>>) = combine(
|
||||||
|
subscriptionInfoListFlow,
|
||||||
|
mContext.defaultVoiceSubscriptionFlow(),
|
||||||
|
mContext.defaultSmsSubscriptionFlow(),
|
||||||
|
::getSummary,
|
||||||
|
).flowOn(Dispatchers.Default)
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
fun getSummary(
|
||||||
|
activeSubscriptionInfoList: List<SubscriptionInfo>,
|
||||||
|
defaultVoiceSubscriptionId: Int,
|
||||||
|
defaultSmsSubscriptionId: Int,
|
||||||
|
): String {
|
||||||
|
if (activeSubscriptionInfoList.isEmpty()) {
|
||||||
|
return mContext.getString(R.string.calls_sms_no_sim)
|
||||||
|
}
|
||||||
|
|
||||||
|
activeSubscriptionInfoList.singleOrNull()?.let {
|
||||||
|
// Set displayName as summary if there is only one valid SIM.
|
||||||
|
if (isInService(it.subscriptionId)) return it.displayName.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
return activeSubscriptionInfoList.joinToString { subInfo ->
|
||||||
|
val displayName = getDisplayName(subInfo)
|
||||||
|
|
||||||
|
val subId = subInfo.subscriptionId
|
||||||
|
val statusResId = getPreferredStatus(
|
||||||
|
subId = subId,
|
||||||
|
subsSize = activeSubscriptionInfoList.size,
|
||||||
|
isCallPreferred = subId == defaultVoiceSubscriptionId,
|
||||||
|
isSmsPreferred = subId == defaultSmsSubscriptionId,
|
||||||
|
)
|
||||||
|
if (statusResId == null) {
|
||||||
|
// If there are 2 or more SIMs and one of these has no preferred status,
|
||||||
|
// set only its displayName as summary.
|
||||||
|
displayName
|
||||||
|
} else {
|
||||||
|
"$displayName (${mContext.getString(statusResId)})"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getPreferredStatus(
|
||||||
|
subId: Int,
|
||||||
|
subsSize: Int,
|
||||||
|
isCallPreferred: Boolean,
|
||||||
|
isSmsPreferred: Boolean,
|
||||||
|
): Int? = when {
|
||||||
|
!isInService(subId) -> {
|
||||||
|
if (subsSize > 1) {
|
||||||
|
R.string.calls_sms_unavailable
|
||||||
|
} else {
|
||||||
|
R.string.calls_sms_temp_unavailable
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
isCallPreferred && isSmsPreferred -> R.string.calls_sms_preferred
|
||||||
|
isCallPreferred -> R.string.calls_sms_calls_preferred
|
||||||
|
isSmsPreferred -> R.string.calls_sms_sms_preferred
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun Context.defaultVoiceSubscriptionFlow(): Flow<Int> =
|
||||||
|
merge(
|
||||||
|
flowOf(null), // kick an initial value
|
||||||
|
broadcastReceiverFlow(
|
||||||
|
IntentFilter(TelephonyManager.ACTION_DEFAULT_VOICE_SUBSCRIPTION_CHANGED)
|
||||||
|
),
|
||||||
|
).map { SubscriptionManager.getDefaultVoiceSubscriptionId() }
|
||||||
|
.conflate().flowOn(Dispatchers.Default)
|
||||||
|
|
||||||
|
private fun Context.defaultSmsSubscriptionFlow(): Flow<Int> =
|
||||||
|
merge(
|
||||||
|
flowOf(null), // kick an initial value
|
||||||
|
broadcastReceiverFlow(
|
||||||
|
IntentFilter(SubscriptionManager.ACTION_DEFAULT_SMS_SUBSCRIPTION_CHANGED)
|
||||||
|
),
|
||||||
|
).map { SubscriptionManager.getDefaultSmsSubscriptionId() }
|
||||||
|
.conflate().flowOn(Dispatchers.Default)
|
||||||
|
|
||||||
|
private class IsInServiceImpl(context: Context) {
|
||||||
|
private val telephonyManager = context.getSystemService(TelephonyManager::class.java)!!
|
||||||
|
|
||||||
|
fun isInService(subId: Int): Boolean {
|
||||||
|
if (!SubscriptionManager.isValidSubscriptionId(subId)) return false
|
||||||
|
|
||||||
|
val serviceState = telephonyManager.createForSubscriptionId(subId).serviceState
|
||||||
|
return Utils.isInService(serviceState)
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,52 @@
|
|||||||
|
/*
|
||||||
|
* 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.network
|
||||||
|
|
||||||
|
import android.app.Application
|
||||||
|
import android.telephony.SubscriptionInfo
|
||||||
|
import android.telephony.SubscriptionManager
|
||||||
|
import androidx.lifecycle.AndroidViewModel
|
||||||
|
import androidx.lifecycle.viewModelScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.asExecutor
|
||||||
|
import kotlinx.coroutines.channels.awaitClose
|
||||||
|
import kotlinx.coroutines.flow.SharingStarted
|
||||||
|
import kotlinx.coroutines.flow.callbackFlow
|
||||||
|
import kotlinx.coroutines.flow.conflate
|
||||||
|
import kotlinx.coroutines.flow.stateIn
|
||||||
|
import kotlinx.coroutines.plus
|
||||||
|
|
||||||
|
class SubscriptionInfoListViewModel(application: Application) : AndroidViewModel(application) {
|
||||||
|
private val scope = viewModelScope + Dispatchers.Default
|
||||||
|
|
||||||
|
val subscriptionInfoListFlow = callbackFlow<List<SubscriptionInfo>> {
|
||||||
|
val subscriptionManager = application.getSystemService(SubscriptionManager::class.java)!!
|
||||||
|
|
||||||
|
val listener = object : SubscriptionManager.OnSubscriptionsChangedListener() {
|
||||||
|
override fun onSubscriptionsChanged() {
|
||||||
|
trySend(subscriptionManager.activeSubscriptionInfoList ?: emptyList())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
subscriptionManager.addOnSubscriptionsChangedListener(
|
||||||
|
Dispatchers.Default.asExecutor(),
|
||||||
|
listener,
|
||||||
|
)
|
||||||
|
|
||||||
|
awaitClose { subscriptionManager.removeOnSubscriptionsChangedListener(listener) }
|
||||||
|
}.conflate().stateIn(scope, SharingStarted.Eagerly, initialValue = emptyList())
|
||||||
|
}
|
@@ -0,0 +1,149 @@
|
|||||||
|
/*
|
||||||
|
* 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.network
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.telephony.SubscriptionInfo
|
||||||
|
import android.telephony.SubscriptionManager
|
||||||
|
import androidx.test.core.app.ApplicationProvider
|
||||||
|
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||||
|
import com.android.settings.R
|
||||||
|
import com.google.common.truth.Truth.assertThat
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4::class)
|
||||||
|
class NetworkProviderCallsSmsControllerTest {
|
||||||
|
private val context: Context = ApplicationProvider.getApplicationContext()
|
||||||
|
|
||||||
|
private var isInService: (Int) -> Boolean = { true }
|
||||||
|
|
||||||
|
private val controller = NetworkProviderCallsSmsController(
|
||||||
|
context = context,
|
||||||
|
preferenceKey = TEST_KEY,
|
||||||
|
getDisplayName = { subInfo -> subInfo.displayName },
|
||||||
|
isInService = { isInService(it) },
|
||||||
|
)
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun getSummary_noSim_returnNoSim() {
|
||||||
|
val summary = controller.getSummary(
|
||||||
|
activeSubscriptionInfoList = emptyList(),
|
||||||
|
defaultVoiceSubscriptionId = SubscriptionManager.INVALID_SUBSCRIPTION_ID,
|
||||||
|
defaultSmsSubscriptionId = SubscriptionManager.INVALID_SUBSCRIPTION_ID,
|
||||||
|
)
|
||||||
|
|
||||||
|
assertThat(summary).isEqualTo(context.getString(R.string.calls_sms_no_sim))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun getSummary_invalidSubId_returnUnavailable() {
|
||||||
|
isInService = { false }
|
||||||
|
|
||||||
|
val summary = controller.getSummary(
|
||||||
|
activeSubscriptionInfoList = listOf(SUB_INFO_1),
|
||||||
|
defaultVoiceSubscriptionId = SubscriptionManager.INVALID_SUBSCRIPTION_ID,
|
||||||
|
defaultSmsSubscriptionId = SubscriptionManager.INVALID_SUBSCRIPTION_ID,
|
||||||
|
)
|
||||||
|
|
||||||
|
assertThat(summary).isEqualTo("Sub 1 (Temporarily unavailable)")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun getSummary_oneIsInvalidSubIdTwoIsValidSubId_returnOneIsUnavailable() {
|
||||||
|
isInService = { it == SUB_INFO_2.subscriptionId }
|
||||||
|
|
||||||
|
val summary = controller.getSummary(
|
||||||
|
activeSubscriptionInfoList = listOf(SUB_INFO_1, SUB_INFO_2),
|
||||||
|
defaultVoiceSubscriptionId = SubscriptionManager.INVALID_SUBSCRIPTION_ID,
|
||||||
|
defaultSmsSubscriptionId = SubscriptionManager.INVALID_SUBSCRIPTION_ID,
|
||||||
|
)
|
||||||
|
|
||||||
|
assertThat(summary).isEqualTo("Sub 1 (unavailable), Sub 2")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun getSummary_oneSubscription_returnDisplayName() {
|
||||||
|
val summary = controller.getSummary(
|
||||||
|
activeSubscriptionInfoList = listOf(SUB_INFO_1),
|
||||||
|
defaultVoiceSubscriptionId = SubscriptionManager.INVALID_SUBSCRIPTION_ID,
|
||||||
|
defaultSmsSubscriptionId = SubscriptionManager.INVALID_SUBSCRIPTION_ID,
|
||||||
|
)
|
||||||
|
|
||||||
|
assertThat(summary).isEqualTo(DISPLAY_NAME_1)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun getSummary_allSubscriptionsHaveNoPreferredStatus_returnDisplayName() {
|
||||||
|
val summary = controller.getSummary(
|
||||||
|
activeSubscriptionInfoList = listOf(SUB_INFO_1, SUB_INFO_2),
|
||||||
|
defaultVoiceSubscriptionId = SubscriptionManager.INVALID_SUBSCRIPTION_ID,
|
||||||
|
defaultSmsSubscriptionId = SubscriptionManager.INVALID_SUBSCRIPTION_ID,
|
||||||
|
)
|
||||||
|
|
||||||
|
assertThat(summary).isEqualTo("Sub 1, Sub 2")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun getSummary_oneSubscriptionsIsCallPreferredTwoIsSmsPreferred_returnStatus() {
|
||||||
|
val summary = controller.getSummary(
|
||||||
|
activeSubscriptionInfoList = listOf(SUB_INFO_1, SUB_INFO_2),
|
||||||
|
defaultVoiceSubscriptionId = SUB_INFO_1.subscriptionId,
|
||||||
|
defaultSmsSubscriptionId = SUB_INFO_2.subscriptionId,
|
||||||
|
)
|
||||||
|
|
||||||
|
assertThat(summary).isEqualTo("Sub 1 (preferred for calls), Sub 2 (preferred for SMS)")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun getSummary_oneSubscriptionsIsSmsPreferredTwoIsCallPreferred_returnStatus() {
|
||||||
|
val summary = controller.getSummary(
|
||||||
|
activeSubscriptionInfoList = listOf(SUB_INFO_1, SUB_INFO_2),
|
||||||
|
defaultVoiceSubscriptionId = SUB_INFO_2.subscriptionId,
|
||||||
|
defaultSmsSubscriptionId = SUB_INFO_1.subscriptionId,
|
||||||
|
)
|
||||||
|
|
||||||
|
assertThat(summary).isEqualTo("Sub 1 (preferred for SMS), Sub 2 (preferred for calls)")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun getSummary_oneSubscriptionsIsSmsPreferredAndIsCallPreferred_returnStatus() {
|
||||||
|
val summary = controller.getSummary(
|
||||||
|
activeSubscriptionInfoList = listOf(SUB_INFO_1, SUB_INFO_2),
|
||||||
|
defaultVoiceSubscriptionId = SUB_INFO_1.subscriptionId,
|
||||||
|
defaultSmsSubscriptionId = SUB_INFO_1.subscriptionId,
|
||||||
|
)
|
||||||
|
|
||||||
|
assertThat(summary).isEqualTo("Sub 1 (preferred), Sub 2")
|
||||||
|
}
|
||||||
|
|
||||||
|
private companion object {
|
||||||
|
const val TEST_KEY = "test_key"
|
||||||
|
const val DISPLAY_NAME_1 = "Sub 1"
|
||||||
|
const val DISPLAY_NAME_2 = "Sub 2"
|
||||||
|
|
||||||
|
val SUB_INFO_1: SubscriptionInfo = SubscriptionInfo.Builder().apply {
|
||||||
|
setId(1)
|
||||||
|
setDisplayName(DISPLAY_NAME_1)
|
||||||
|
}.build()
|
||||||
|
|
||||||
|
val SUB_INFO_2: SubscriptionInfo = SubscriptionInfo.Builder().apply {
|
||||||
|
setId(2)
|
||||||
|
setDisplayName(DISPLAY_NAME_2)
|
||||||
|
}.build()
|
||||||
|
}
|
||||||
|
}
|
@@ -1,360 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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 androidx.lifecycle.Lifecycle.Event;
|
|
||||||
|
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
|
||||||
|
|
||||||
import static org.junit.Assert.assertTrue;
|
|
||||||
import static org.mockito.Mockito.spy;
|
|
||||||
import static org.mockito.Mockito.when;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.os.Looper;
|
|
||||||
import android.telephony.SubscriptionInfo;
|
|
||||||
import android.telephony.SubscriptionManager;
|
|
||||||
import android.telephony.TelephonyManager;
|
|
||||||
import android.text.TextUtils;
|
|
||||||
|
|
||||||
import androidx.lifecycle.LifecycleOwner;
|
|
||||||
import androidx.lifecycle.LifecycleRegistry;
|
|
||||||
import androidx.preference.PreferenceManager;
|
|
||||||
import androidx.preference.PreferenceScreen;
|
|
||||||
import androidx.test.annotation.UiThreadTest;
|
|
||||||
import androidx.test.core.app.ApplicationProvider;
|
|
||||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
|
||||||
|
|
||||||
import com.android.settings.testutils.ResourcesUtils;
|
|
||||||
import com.android.settingslib.RestrictedPreference;
|
|
||||||
import com.android.settingslib.core.lifecycle.Lifecycle;
|
|
||||||
import com.android.settingslib.mobile.dataservice.SubscriptionInfoEntity;
|
|
||||||
|
|
||||||
import org.junit.Before;
|
|
||||||
import org.junit.Test;
|
|
||||||
import org.junit.runner.RunWith;
|
|
||||||
import org.mockito.Mock;
|
|
||||||
import org.mockito.MockitoAnnotations;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
|
|
||||||
@RunWith(AndroidJUnit4.class)
|
|
||||||
public class NetworkProviderCallsSmsControllerTest {
|
|
||||||
|
|
||||||
private static final String SUB_ID_1 = "1";
|
|
||||||
private static final String SUB_ID_2 = "2";
|
|
||||||
private static final String INVALID_SUB_ID = "-1";
|
|
||||||
private static final String KEY_PREFERENCE_CALLS_SMS = "calls_and_sms";
|
|
||||||
private static final String DISPLAY_NAME_1 = "Sub 1";
|
|
||||||
private static final String DISPLAY_NAME_2 = "Sub 2";
|
|
||||||
private static final String SUB_MCC_1 = "123";
|
|
||||||
private static final String SUB_MNC_1 = "456";
|
|
||||||
private static final String SUB_MCC_2 = "223";
|
|
||||||
private static final String SUB_MNC_2 = "456";
|
|
||||||
private static final String SUB_COUNTRY_ISO_1 = "Sub 1";
|
|
||||||
private static final String SUB_COUNTRY_ISO_2 = "Sub 2";
|
|
||||||
|
|
||||||
@Mock
|
|
||||||
private SubscriptionInfoEntity mSubInfo1;
|
|
||||||
@Mock
|
|
||||||
private SubscriptionInfoEntity mSubInfo2;
|
|
||||||
@Mock
|
|
||||||
private Lifecycle mLifecycle;
|
|
||||||
@Mock
|
|
||||||
private LifecycleOwner mLifecycleOwner;
|
|
||||||
|
|
||||||
private LifecycleRegistry mLifecycleRegistry;
|
|
||||||
private MockNetworkProviderCallsSmsController mController;
|
|
||||||
private PreferenceManager mPreferenceManager;
|
|
||||||
private PreferenceScreen mPreferenceScreen;
|
|
||||||
private RestrictedPreference mPreference;
|
|
||||||
private Context mContext;
|
|
||||||
private List<SubscriptionInfoEntity> mSubscriptionInfoEntityList = new ArrayList<>();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Mock the NetworkProviderCallsSmsController that allows one to set a default voice
|
|
||||||
* and SMS subscription ID.
|
|
||||||
*/
|
|
||||||
private class MockNetworkProviderCallsSmsController extends
|
|
||||||
com.android.settings.network.NetworkProviderCallsSmsController {
|
|
||||||
public MockNetworkProviderCallsSmsController(Context context, Lifecycle lifecycle,
|
|
||||||
LifecycleOwner lifecycleOwner) {
|
|
||||||
super(context, lifecycle, lifecycleOwner);
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<SubscriptionInfoEntity> mSubscriptionInfoEntity;
|
|
||||||
private boolean mIsInService;
|
|
||||||
private int mDefaultVoiceSubscriptionId;
|
|
||||||
private int mDefaultSmsSubscriptionId;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected List<SubscriptionInfoEntity> getSubscriptionInfoList() {
|
|
||||||
return mSubscriptionInfoEntity;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setSubscriptionInfoList(List<SubscriptionInfoEntity> list) {
|
|
||||||
mSubscriptionInfoEntity = list;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected boolean isInService(int subId) {
|
|
||||||
return mIsInService;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setInService(boolean inService) {
|
|
||||||
mIsInService = inService;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected int getDefaultVoiceSubscriptionId() {
|
|
||||||
return mDefaultVoiceSubscriptionId;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected int getDefaultSmsSubscriptionId() {
|
|
||||||
return mDefaultSmsSubscriptionId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setDefaultVoiceSubscriptionId(int subscriptionId) {
|
|
||||||
mDefaultVoiceSubscriptionId = subscriptionId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setDefaultSmsSubscriptionId(int subscriptionId) {
|
|
||||||
mDefaultSmsSubscriptionId = subscriptionId;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Before
|
|
||||||
public void setUp() {
|
|
||||||
MockitoAnnotations.initMocks(this);
|
|
||||||
mContext = spy(ApplicationProvider.getApplicationContext());
|
|
||||||
|
|
||||||
if (Looper.myLooper() == null) {
|
|
||||||
Looper.prepare();
|
|
||||||
}
|
|
||||||
|
|
||||||
mPreferenceManager = new PreferenceManager(mContext);
|
|
||||||
mPreferenceScreen = mPreferenceManager.createPreferenceScreen(mContext);
|
|
||||||
mPreference = new RestrictedPreference(mContext);
|
|
||||||
mPreference.setKey(KEY_PREFERENCE_CALLS_SMS);
|
|
||||||
mController = new MockNetworkProviderCallsSmsController(mContext, mLifecycle,
|
|
||||||
mLifecycleOwner);
|
|
||||||
mController.setInService(true);
|
|
||||||
mLifecycleRegistry = new LifecycleRegistry(mLifecycleOwner);
|
|
||||||
when(mLifecycleOwner.getLifecycle()).thenReturn(mLifecycleRegistry);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void displayPreferenceWithLifecycle() {
|
|
||||||
mLifecycleRegistry.addObserver(mController);
|
|
||||||
mPreferenceScreen.addPreference(mPreference);
|
|
||||||
mController.displayPreference(mPreferenceScreen);
|
|
||||||
mLifecycleRegistry.handleLifecycleEvent(Event.ON_RESUME);
|
|
||||||
}
|
|
||||||
|
|
||||||
private String setSummaryResId(String resName) {
|
|
||||||
return ResourcesUtils.getResourcesString(mContext, resName);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
@UiThreadTest
|
|
||||||
public void getSummary_noSim_returnNoSim() {
|
|
||||||
mController.setSubscriptionInfoList(mSubscriptionInfoEntityList);
|
|
||||||
displayPreferenceWithLifecycle();
|
|
||||||
|
|
||||||
assertTrue(TextUtils.equals(mController.getSummary(),
|
|
||||||
setSummaryResId("calls_sms_no_sim")));
|
|
||||||
}
|
|
||||||
|
|
||||||
private SubscriptionInfoEntity setupSubscriptionInfoEntity(String subId, int slotId,
|
|
||||||
int carrierId, String displayName, String mcc, String mnc, String countryIso,
|
|
||||||
int cardId, boolean isValid, boolean isActive, boolean isAvailable) {
|
|
||||||
return new SubscriptionInfoEntity(subId, slotId, carrierId,
|
|
||||||
displayName, displayName, 0, mcc, mnc, countryIso, false, cardId,
|
|
||||||
TelephonyManager.DEFAULT_PORT_INDEX, false, null,
|
|
||||||
SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM, displayName, false,
|
|
||||||
"1234567890", true, false, isValid,
|
|
||||||
true, isActive, isAvailable, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
@UiThreadTest
|
|
||||||
public void getSummary_invalidSubId_returnUnavailable() {
|
|
||||||
|
|
||||||
mSubInfo1 = setupSubscriptionInfoEntity(INVALID_SUB_ID,
|
|
||||||
SubscriptionManager.INVALID_SIM_SLOT_INDEX, TelephonyManager.UNKNOWN_CARRIER_ID,
|
|
||||||
DISPLAY_NAME_1, SUB_MCC_1, SUB_MNC_1, SUB_COUNTRY_ISO_1,
|
|
||||||
TelephonyManager.UNINITIALIZED_CARD_ID, false, true, true);
|
|
||||||
mSubscriptionInfoEntityList.add(mSubInfo1);
|
|
||||||
mController.setSubscriptionInfoList(mSubscriptionInfoEntityList);
|
|
||||||
displayPreferenceWithLifecycle();
|
|
||||||
|
|
||||||
final StringBuilder summary = new StringBuilder();
|
|
||||||
summary.append(DISPLAY_NAME_1)
|
|
||||||
.append(" (")
|
|
||||||
.append(setSummaryResId("calls_sms_temp_unavailable"))
|
|
||||||
.append(")");
|
|
||||||
|
|
||||||
assertTrue(TextUtils.equals(mController.getSummary(), summary));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
@UiThreadTest
|
|
||||||
public void getSummary_oneIsInvalidSubIdTwoIsValidSubId_returnOneIsUnavailable() {
|
|
||||||
|
|
||||||
mSubInfo1 = setupSubscriptionInfoEntity(INVALID_SUB_ID,
|
|
||||||
SubscriptionManager.INVALID_SIM_SLOT_INDEX, TelephonyManager.UNKNOWN_CARRIER_ID,
|
|
||||||
DISPLAY_NAME_1, SUB_MCC_1, SUB_MNC_1, SUB_COUNTRY_ISO_1,
|
|
||||||
TelephonyManager.UNINITIALIZED_CARD_ID, false, true, true);
|
|
||||||
mSubInfo2 = setupSubscriptionInfoEntity(SUB_ID_2, 1, 1, DISPLAY_NAME_2, SUB_MCC_2,
|
|
||||||
SUB_MNC_2, SUB_COUNTRY_ISO_2, 1, true, true, true);
|
|
||||||
mSubscriptionInfoEntityList.add(mSubInfo1);
|
|
||||||
mSubscriptionInfoEntityList.add(mSubInfo2);
|
|
||||||
mController.setSubscriptionInfoList(mSubscriptionInfoEntityList);
|
|
||||||
displayPreferenceWithLifecycle();
|
|
||||||
|
|
||||||
final StringBuilder summary = new StringBuilder();
|
|
||||||
summary.append(DISPLAY_NAME_1)
|
|
||||||
.append(" (")
|
|
||||||
.append(setSummaryResId("calls_sms_unavailable"))
|
|
||||||
.append(")")
|
|
||||||
.append(", ")
|
|
||||||
.append(DISPLAY_NAME_2);
|
|
||||||
|
|
||||||
assertTrue(TextUtils.equals(mController.getSummary(), summary));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
@UiThreadTest
|
|
||||||
public void getSummary_oneSubscription_returnDisplayName() {
|
|
||||||
|
|
||||||
mSubInfo1 = setupSubscriptionInfoEntity(SUB_ID_1, 1, 1, DISPLAY_NAME_1, SUB_MCC_1,
|
|
||||||
SUB_MNC_1, SUB_COUNTRY_ISO_1, 1, true, true, true);
|
|
||||||
mSubscriptionInfoEntityList.add(mSubInfo1);
|
|
||||||
mController.setSubscriptionInfoList(mSubscriptionInfoEntityList);
|
|
||||||
displayPreferenceWithLifecycle();
|
|
||||||
|
|
||||||
assertThat(mPreference.getSummary()).isEqualTo(DISPLAY_NAME_1);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
@UiThreadTest
|
|
||||||
public void getSummary_allSubscriptionsHaveNoPreferredStatus_returnDisplayName() {
|
|
||||||
|
|
||||||
mSubInfo1 = setupSubscriptionInfoEntity(SUB_ID_1, 1, 1, DISPLAY_NAME_1, SUB_MCC_1,
|
|
||||||
SUB_MNC_1, SUB_COUNTRY_ISO_1, 1, true, true, true);
|
|
||||||
mSubInfo2 = setupSubscriptionInfoEntity(SUB_ID_2, 1, 1, DISPLAY_NAME_2, SUB_MCC_2,
|
|
||||||
SUB_MNC_2, SUB_COUNTRY_ISO_2, 1, true, true, true);
|
|
||||||
mSubscriptionInfoEntityList.add(mSubInfo1);
|
|
||||||
mSubscriptionInfoEntityList.add(mSubInfo2);
|
|
||||||
mController.setSubscriptionInfoList(mSubscriptionInfoEntityList);
|
|
||||||
displayPreferenceWithLifecycle();
|
|
||||||
|
|
||||||
final StringBuilder summary = new StringBuilder();
|
|
||||||
summary.append(DISPLAY_NAME_1).append(", ").append(DISPLAY_NAME_2);
|
|
||||||
|
|
||||||
assertTrue(TextUtils.equals(mController.getSummary(), summary));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
@UiThreadTest
|
|
||||||
public void getSummary_oneSubscriptionsIsCallPreferredTwoIsSmsPreferred_returnStatus() {
|
|
||||||
|
|
||||||
mController.setDefaultVoiceSubscriptionId(Integer.parseInt(SUB_ID_1));
|
|
||||||
mController.setDefaultSmsSubscriptionId(Integer.parseInt(SUB_ID_2));
|
|
||||||
|
|
||||||
mSubInfo1 = setupSubscriptionInfoEntity(SUB_ID_1, 1, 1, DISPLAY_NAME_1, SUB_MCC_1,
|
|
||||||
SUB_MNC_1, SUB_COUNTRY_ISO_1, 1, true, true, true);
|
|
||||||
mSubInfo2 = setupSubscriptionInfoEntity(SUB_ID_2, 1, 1, DISPLAY_NAME_2, SUB_MCC_2,
|
|
||||||
SUB_MNC_2, SUB_COUNTRY_ISO_2, 1, true, true, true);
|
|
||||||
mSubscriptionInfoEntityList.add(mSubInfo1);
|
|
||||||
mSubscriptionInfoEntityList.add(mSubInfo2);
|
|
||||||
mController.setSubscriptionInfoList(mSubscriptionInfoEntityList);
|
|
||||||
displayPreferenceWithLifecycle();
|
|
||||||
|
|
||||||
final StringBuilder summary = new StringBuilder();
|
|
||||||
summary.append(DISPLAY_NAME_1)
|
|
||||||
.append(" (")
|
|
||||||
.append(setSummaryResId("calls_sms_calls_preferred"))
|
|
||||||
.append(")")
|
|
||||||
.append(", ")
|
|
||||||
.append(DISPLAY_NAME_2)
|
|
||||||
.append(" (")
|
|
||||||
.append(setSummaryResId("calls_sms_sms_preferred"))
|
|
||||||
.append(")");
|
|
||||||
|
|
||||||
assertTrue(TextUtils.equals(mController.getSummary(), summary));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
@UiThreadTest
|
|
||||||
public void getSummary_oneSubscriptionsIsSmsPreferredTwoIsCallPreferred_returnStatus() {
|
|
||||||
|
|
||||||
mController.setDefaultSmsSubscriptionId(Integer.parseInt(SUB_ID_1));
|
|
||||||
mController.setDefaultVoiceSubscriptionId(Integer.parseInt(SUB_ID_2));
|
|
||||||
|
|
||||||
mSubInfo1 = setupSubscriptionInfoEntity(SUB_ID_1, 1, 1, DISPLAY_NAME_1, SUB_MCC_1,
|
|
||||||
SUB_MNC_1, SUB_COUNTRY_ISO_1, 1, true, true, true);
|
|
||||||
mSubInfo2 = setupSubscriptionInfoEntity(SUB_ID_2, 2, 2, DISPLAY_NAME_2, SUB_MCC_2,
|
|
||||||
SUB_MNC_2, SUB_COUNTRY_ISO_2, 1, true, true, true);
|
|
||||||
mSubscriptionInfoEntityList.add(mSubInfo1);
|
|
||||||
mSubscriptionInfoEntityList.add(mSubInfo2);
|
|
||||||
mController.setSubscriptionInfoList(mSubscriptionInfoEntityList);
|
|
||||||
displayPreferenceWithLifecycle();
|
|
||||||
|
|
||||||
final StringBuilder summary = new StringBuilder();
|
|
||||||
summary.append(DISPLAY_NAME_1)
|
|
||||||
.append(" (")
|
|
||||||
.append(setSummaryResId("calls_sms_sms_preferred"))
|
|
||||||
.append(")")
|
|
||||||
.append(", ")
|
|
||||||
.append(DISPLAY_NAME_2)
|
|
||||||
.append(" (")
|
|
||||||
.append(setSummaryResId("calls_sms_calls_preferred"))
|
|
||||||
.append(")");
|
|
||||||
|
|
||||||
assertTrue(TextUtils.equals(mController.getSummary(), summary));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
@UiThreadTest
|
|
||||||
public void getSummary_oneSubscriptionsIsSmsPreferredAndIsCallPreferred_returnStatus() {
|
|
||||||
|
|
||||||
mController.setDefaultSmsSubscriptionId(Integer.parseInt(SUB_ID_1));
|
|
||||||
mController.setDefaultVoiceSubscriptionId(Integer.parseInt(SUB_ID_1));
|
|
||||||
|
|
||||||
mSubInfo1 = setupSubscriptionInfoEntity(SUB_ID_1, 1, 1, DISPLAY_NAME_1, SUB_MCC_1,
|
|
||||||
SUB_MNC_1, SUB_COUNTRY_ISO_1, 1, true, true, true);
|
|
||||||
mSubInfo2 = setupSubscriptionInfoEntity(SUB_ID_2, 1, 1, DISPLAY_NAME_2, SUB_MCC_2,
|
|
||||||
SUB_MNC_2, SUB_COUNTRY_ISO_2, 1, true, true, true);
|
|
||||||
mSubscriptionInfoEntityList.add(mSubInfo1);
|
|
||||||
mSubscriptionInfoEntityList.add(mSubInfo2);
|
|
||||||
mController.setSubscriptionInfoList(mSubscriptionInfoEntityList);
|
|
||||||
displayPreferenceWithLifecycle();
|
|
||||||
|
|
||||||
final StringBuilder summary = new StringBuilder();
|
|
||||||
summary.append(DISPLAY_NAME_1)
|
|
||||||
.append(" (")
|
|
||||||
.append(setSummaryResId("calls_sms_preferred"))
|
|
||||||
.append(")")
|
|
||||||
.append(", ")
|
|
||||||
.append(DISPLAY_NAME_2);
|
|
||||||
|
|
||||||
assertTrue(TextUtils.equals(mController.getSummary(), summary));
|
|
||||||
}
|
|
||||||
}
|
|
Reference in New Issue
Block a user