Fixed network interfaces on Android
This commit is contained in:
parent
4d395b3b72
commit
bfdc9e312f
14 changed files with 212 additions and 5 deletions
|
@ -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" />
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
)
|
||||
}
|
||||
|
|
|
@ -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 }
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -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";
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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"};
|
||||
|
|
|
@ -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()) {
|
||||
|
|
Loading…
Add table
Reference in a new issue