Fixed network interfaces on Android

This commit is contained in:
Timotej Leginus 2023-06-10 22:52:50 +02:00
parent 4d395b3b72
commit bfdc9e312f
14 changed files with 212 additions and 5 deletions

View file

@ -11,6 +11,7 @@ SPDX-License-Identifier: GPL-3.0-or-later
<uses-feature android:name="android.software.leanback" android:required="false" />
<uses-feature android:name="android.hardware.vulkan.version" android:version="0x401000" android:required="true" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.NFC" />

View file

@ -10,6 +10,7 @@ import android.content.Context
import org.yuzu.yuzu_emu.utils.DirectoryInitialization
import org.yuzu.yuzu_emu.utils.DocumentsTree
import org.yuzu.yuzu_emu.utils.GpuDriverHelper
import org.yuzu.yuzu_emu.utils.NetworkHelper
import java.io.File
fun Context.getPublicFilesDir() : File = getExternalFilesDir(null) ?: filesDir
@ -46,6 +47,7 @@ class YuzuApplication : Application() {
documentsTree = DocumentsTree()
DirectoryInitialization.start(applicationContext)
GpuDriverHelper.initializeDriverParameters(applicationContext)
NetworkHelper.setRoutes(applicationContext)
NativeLibrary.logDeviceInfo()
createNotificationChannels();

View file

@ -107,6 +107,7 @@ class Settings {
const val SECTION_RENDERER = "Renderer"
const val SECTION_AUDIO = "Audio"
const val SECTION_CPU = "Cpu"
const val SECTION_NETWORK = "Network"
const val SECTION_THEME = "Theme"
const val SECTION_DEBUG = "Debug"
@ -151,6 +152,7 @@ class Settings {
SECTION_SYSTEM,
SECTION_RENDERER,
SECTION_AUDIO,
SECTION_NETWORK,
SECTION_CPU
)
}

View file

@ -8,7 +8,8 @@ enum class StringSetting(
override val section: String,
override val defaultValue: String
) : AbstractStringSetting {
CUSTOM_RTC("custom_rtc", Settings.SECTION_SYSTEM, "0");
CUSTOM_RTC("custom_rtc", Settings.SECTION_SYSTEM, "0"),
NETWORK_ROUTE("network_route", Settings.SECTION_NETWORK, ";;;;");
override var string: String = defaultValue
@ -27,7 +28,8 @@ enum class StringSetting(
companion object {
private val NOT_RUNTIME_EDITABLE = listOf(
CUSTOM_RTC
CUSTOM_RTC,
NETWORK_ROUTE
)
fun from(key: String): StringSetting? = StringSetting.values().firstOrNull { it.key == key }

View file

@ -35,5 +35,6 @@ abstract class SettingsItem(
const val TYPE_STRING_SINGLE_CHOICE = 5
const val TYPE_DATETIME_SETTING = 6
const val TYPE_RUNNABLE = 7
const val TYPE_TEXT_SETTING = 8
}
}

View file

@ -0,0 +1,31 @@
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
package org.yuzu.yuzu_emu.features.settings.model.view
import org.yuzu.yuzu_emu.features.settings.model.AbstractSetting
import org.yuzu.yuzu_emu.features.settings.model.AbstractStringSetting
class TextSetting(
setting: AbstractSetting?,
titleId: Int,
descriptionId: Int,
val key: String? = null,
private val defaultValue: String? = null
) : SettingsItem(setting, titleId, descriptionId) {
override val type = TYPE_TEXT_SETTING
val value: String
get() = if (setting != null) {
val setting = setting as AbstractStringSetting
setting.string
} else {
defaultValue!!
}
fun setSelectedValue(string: String): AbstractStringSetting {
val stringSetting = setting as AbstractStringSetting
stringSetting.string = string
return stringSetting
}
}

View file

@ -7,13 +7,14 @@ import android.content.Context
import android.content.DialogInterface
import android.icu.util.Calendar
import android.icu.util.TimeZone
import android.text.TextWatcher
import android.text.format.DateFormat
import android.view.LayoutInflater
import android.view.ViewGroup
import android.widget.TextView
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.setFragmentResultListener
import androidx.core.widget.doAfterTextChanged
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.datepicker.MaterialDatePicker
import com.google.android.material.dialog.MaterialAlertDialogBuilder
@ -21,6 +22,7 @@ import com.google.android.material.slider.Slider
import com.google.android.material.timepicker.MaterialTimePicker
import com.google.android.material.timepicker.TimeFormat
import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.databinding.DialogEditTextBinding
import org.yuzu.yuzu_emu.databinding.DialogSliderBinding
import org.yuzu.yuzu_emu.databinding.ListItemSettingBinding
import org.yuzu.yuzu_emu.databinding.ListItemSettingSwitchBinding
@ -83,6 +85,10 @@ class SettingsAdapter(
RunnableViewHolder(ListItemSettingBinding.inflate(inflater), this)
}
SettingsItem.TYPE_TEXT_SETTING -> {
TextSettingViewHolder(ListItemSettingBinding.inflate(inflater), this)
}
else -> {
// TODO: Create an error view since we can't return null now
HeaderViewHolder(ListItemSettingsHeaderBinding.inflate(inflater), this)
@ -167,6 +173,7 @@ class SettingsAdapter(
.setSelection(storedTime)
.setTitleText(R.string.select_rtc_date)
.build()
val timePicker: MaterialTimePicker = MaterialTimePicker.Builder()
.setTimeFormat(timeFormat)
.setHour(calendar.get(Calendar.HOUR_OF_DAY))
@ -199,6 +206,38 @@ class SettingsAdapter(
)
}
fun onTextSettingClick(item: TextSetting, position: Int) {
clickedItem = item
clickedPosition = position
var value = item.value
val inflater = LayoutInflater.from(context)
val editTextBinding = DialogEditTextBinding.inflate(inflater)
editTextBinding.editText.setText(value)
editTextBinding.editText.doAfterTextChanged {
value = it.toString()
}
dialog = MaterialAlertDialogBuilder(context)
.setTitle(item.nameId)
.setView(editTextBinding.root)
.setPositiveButton(android.R.string.ok) { _, _ ->
if (item.value != value) {
fragmentView.onSettingChanged()
}
notifyItemChanged(clickedPosition)
val setting = item.setSelectedValue(value)
fragmentView.putSetting(setting)
clickedItem = null
}
.setNegativeButton(android.R.string.cancel, defaultCancelListener)
.show()
}
fun onSliderClick(item: SliderSetting, position: Int) {
clickedItem = item
clickedPosition = position

View file

@ -7,7 +7,6 @@ import android.content.SharedPreferences
import android.os.Build
import android.text.TextUtils
import androidx.preference.PreferenceManager
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.YuzuApplication
import org.yuzu.yuzu_emu.features.settings.model.AbstractBooleanSetting
@ -67,6 +66,7 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView)
Settings.SECTION_SYSTEM -> addSystemSettings(sl)
Settings.SECTION_RENDERER -> addGraphicsSettings(sl)
Settings.SECTION_AUDIO -> addAudioSettings(sl)
Settings.SECTION_NETWORK -> addNetworkSettings(sl)
Settings.SECTION_THEME -> addThemeSettings(sl)
Settings.SECTION_DEBUG -> addDebugSettings(sl)
else -> {
@ -102,6 +102,13 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView)
Settings.SECTION_RENDERER
)
)
add(
SubmenuSetting(
R.string.preferences_network,
0,
Settings.SECTION_NETWORK
)
)
add(
SubmenuSetting(
R.string.preferences_audio,
@ -437,6 +444,22 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView)
}
}
private fun addNetworkSettings(sl: ArrayList<SettingsItem>) {
settingsActivity.setToolbarTitle(settingsActivity.getString(R.string.preferences_network))
sl.apply {
add(
TextSetting(
StringSetting.NETWORK_ROUTE,
R.string.set_network_route,
R.string.network_route_desc,
StringSetting.NETWORK_ROUTE.key,
StringSetting.NETWORK_ROUTE.defaultValue
)
)
}
}
private fun addDebugSettings(sl: ArrayList<SettingsItem>) {
settingsActivity.setToolbarTitle(settingsActivity.getString(R.string.preferences_debug))
sl.apply {

View file

@ -0,0 +1,44 @@
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
package org.yuzu.yuzu_emu.features.settings.ui.viewholder
import android.view.View
import org.yuzu.yuzu_emu.databinding.ListItemSettingBinding
import org.yuzu.yuzu_emu.features.settings.model.view.DateTimeSetting
import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem
import org.yuzu.yuzu_emu.features.settings.model.view.TextSetting
import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter
import java.time.Instant
import java.time.ZoneId
import java.time.ZonedDateTime
import java.time.format.DateTimeFormatter
import java.time.format.FormatStyle
class TextSettingViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAdapter) :
SettingViewHolder(binding.root, adapter) {
private lateinit var setting: TextSetting
override fun bind(item: SettingsItem) {
setting = item as TextSetting
binding.textSettingName.setText(item.nameId)
if (item.descriptionId != 0) {
binding.textSettingDescription.setText(item.descriptionId)
binding.textSettingDescription.visibility = View.VISIBLE
}
}
override fun onClick(clicked: View) {
if (setting.isEditable) {
adapter.onTextSettingClick(setting, bindingAdapterPosition)
}
}
override fun onLongClick(clicked: View): Boolean {
if (setting.isEditable) {
return adapter.onLongClick(setting.setting!!, bindingAdapterPosition)
}
return false
}
}

View file

@ -0,0 +1,20 @@
package org.yuzu.yuzu_emu.utils
import android.content.Context
import android.net.ConnectivityManager
object NetworkHelper {
fun setRoutes(context: Context) {
val connectivity =
context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
val lp = connectivity.getLinkProperties(connectivity.activeNetwork)
// lp.routes
}
}

View file

@ -244,6 +244,11 @@ void Config::ReadValues() {
ReadSetting("Audio", Settings::values.audio_output_device_id);
ReadSetting("Audio", Settings::values.volume);
// Network
Settings::values.network_route =
config->GetString("Network", "network_route", "");
// Miscellaneous
// log_filter has a different default here than from common
Settings::values.log_filter = "*:Info";

View file

@ -151,6 +151,10 @@
<string name="use_custom_rtc_description">Allows you to set a custom real-time clock separate from your current system time.</string>
<string name="set_custom_rtc">Set custom RTC</string>
<!-- Network settings strings -->
<string name="network_route_desc">Sets the default network route</string>
<string name="set_network_route">Set network route</string>
<!-- Graphics settings strings -->
<string name="renderer_api">API</string>
<string name="renderer_accuracy">Accuracy level</string>
@ -203,6 +207,7 @@
<string name="preferences_settings">Settings</string>
<string name="preferences_general">General</string>
<string name="preferences_system">System</string>
<string name="preferences_network">Network</string>
<string name="preferences_graphics">Graphics</string>
<string name="preferences_audio">Audio</string>
<string name="preferences_theme">Theme and color</string>

View file

@ -581,6 +581,7 @@ struct Values {
// Network
Setting<std::string> network_interface{std::string(), "network_interface"};
Setting<std::string> network_route{std::string(), "network_route"};
// WebService
Setting<bool> enable_telemetry{true, "enable_telemetry"};

View file

@ -6,6 +6,8 @@
#include <sstream>
#include <vector>
#include <boost/algorithm/string.hpp>
#include "common/bit_cast.h"
#include "common/common_types.h"
#include "common/logging/log.h"
@ -20,6 +22,8 @@
#include <cerrno>
#include <ifaddrs.h>
#include <net/if.h>
#include <arpa/inet.h>
#endif
namespace Network {
@ -91,8 +95,31 @@ std::vector<NetworkInterface> GetAvailableNetworkInterfaces() {
return result;
}
#else
#elif defined(__ANDROID__)
std::vector<NetworkInterface> GetAvailableNetworkInterfaces() {
std::vector<NetworkInterface> result;
std::vector<std::string> route_parts;
boost::split(route_parts, Settings::values.network_route.GetValue(), boost::is_any_of(";"));
struct in_addr ip{}, sm{}, gw{};
inet_pton(AF_INET, route_parts[1].c_str(), &ip);
inet_pton(AF_INET, route_parts[2].c_str(), &sm);
inet_pton(AF_INET, route_parts[3].c_str(), &gw);
result.emplace_back(NetworkInterface{
.name{route_parts[0]},
.ip_address{ip},
.subnet_mask{sm},
.gateway{gw}
});
return result;
}
#else
std::vector<NetworkInterface> GetAvailableNetworkInterfaces() {
struct ifaddrs* ifaddr = nullptr;
@ -187,6 +214,10 @@ std::vector<NetworkInterface> GetAvailableNetworkInterfaces() {
#endif
std::optional<NetworkInterface> GetSelectedNetworkInterface() {
#ifdef __ANDROID__
Network::SelectFirstNetworkInterface(); // TODO ANDROID
#endif
const auto& selected_network_interface = Settings::values.network_interface.GetValue();
const auto network_interfaces = Network::GetAvailableNetworkInterfaces();
if (network_interfaces.empty()) {