Metered Wi-Fi toggle (#35293)

* draft

* here too

* fixes

* fix

* ugh more fix, wifiManager is craze

* more

* be optimistic and let refresh happen naturally, the immediate refresh causes some paths/active connect to temporarily be unavailable

selfdrive/ui/qt/network/wifi_manager.cc: DBus call error: "Did not receive a reply. Possible causes include: the remote application did not send a reply, the message bus security policy blocked the reply, the re
ply timeout expired, or the network connection was broken."
selfdrive/ui/qt/network/wifi_manager.cc: DBus call error: "Object path cannot be empty"

* nm is slow -- it takes 2s to commit to disk, and dbus errors are raised if you try again while previous is running (this is an ubuntu 24.04 bug)

* nice experience

* rm

* minor

* clean up

* self-explanatory

* rename

* rm this too

* revert

* draft

* Revert "draft"

This reverts commit 15283d9778.

* Reapply "draft"

This reverts commit 8629921b00.

* rm colors

* trinary, bit more code

* choose default when disabled

* only if enabling, wait for disable as normal

* remove original binary toggle

* clean up

* collapse

* clean up wifimanager

* update comment

* lite is a word
special_tr_rebased^2
Shane Smiskol 2 months ago committed by GitHub
parent c9f3cd5ad2
commit f38a98fc09
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 2
      pyproject.toml
  2. 46
      selfdrive/ui/qt/network/networking.cc
  3. 3
      selfdrive/ui/qt/network/networking.h
  4. 39
      selfdrive/ui/qt/network/wifi_manager.cc
  5. 7
      selfdrive/ui/qt/network/wifi_manager.h
  6. 4
      selfdrive/ui/qt/widgets/controls.h

@ -169,7 +169,7 @@ testpaths = [
[tool.codespell]
quiet-level = 3
# if you've got a short variable name that's getting flagged, add it here
ignore-words-list = "bu,ro,te,ue,alo,hda,ois,nam,nams,ned,som,parm,setts,inout,warmup,bumb,nd,sie,preints,whit,indexIn,ws,uint,grey,deque,stdio,amin,BA,LITE,atEnd,UIs,errorString,arange,FocusIn,od,tim,relA,hist,copyable,jupyter,thead,TGE,abl"
ignore-words-list = "bu,ro,te,ue,alo,hda,ois,nam,nams,ned,som,parm,setts,inout,warmup,bumb,nd,sie,preints,whit,indexIn,ws,uint,grey,deque,stdio,amin,BA,LITE,atEnd,UIs,errorString,arange,FocusIn,od,tim,relA,hist,copyable,jupyter,thead,TGE,abl,lite"
builtin = "clear,rare,informal,code,names,en-GB_to_en-US"
skip = "./third_party/*, ./tinygrad/*, ./tinygrad_repo/*, ./msgq/*, ./panda/*, ./opendbc/*, ./opendbc_repo/*, ./rednose/*, ./rednose_repo/*, ./teleoprtc/*, ./teleoprtc_repo/*, *.ts, uv.lock, *.onnx, ./cereal/gen/*, */c_generated_code/*, docs/assets/*"

@ -173,14 +173,36 @@ AdvancedNetworking::AdvancedNetworking(QWidget* parent, WifiManager* wifi): QWid
});
list->addItem(editApnButton);
// Metered toggle
// Cellular metered toggle (prime lite or none)
const bool metered = params.getBool("GsmMetered");
meteredToggle = new ToggleControl(tr("Cellular Metered"), tr("Prevent large data uploads when on a metered connection"), "", metered);
QObject::connect(meteredToggle, &SshToggle::toggleFlipped, [=](bool state) {
cellularMeteredToggle = new ToggleControl(tr("Cellular Metered"), tr("Prevent large data uploads when on a metered cellular connection"), "", metered);
QObject::connect(cellularMeteredToggle, &SshToggle::toggleFlipped, [=](bool state) {
params.putBool("GsmMetered", state);
wifi->updateGsmSettings(params.getBool("GsmRoaming"), QString::fromStdString(params.get("GsmApn")), state);
});
list->addItem(meteredToggle);
list->addItem(cellularMeteredToggle);
// Wi-Fi metered toggle
std::vector<QString> metered_button_texts{tr("default"), tr("metered"), tr("unmetered")};
wifiMeteredToggle = new MultiButtonControl(tr("Wi-Fi Network Metered"), tr("Prevent large data uploads when on a metered Wi-FI connection"), "", metered_button_texts);
QObject::connect(wifiMeteredToggle, &MultiButtonControl::buttonClicked, [=](int id) {
wifiMeteredToggle->setEnabled(false);
MeteredType metered = MeteredType::UNKNOWN;
if (id == NM_METERED_YES) {
metered = MeteredType::YES;
} else if (id == NM_METERED_NO) {
metered = MeteredType::NO;
}
auto pending_call = wifi->setCurrentNetworkMetered(metered);
if (pending_call) {
QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(*pending_call);
QObject::connect(watcher, &QDBusPendingCallWatcher::finished, this, [=]() {
refresh();
watcher->deleteLater();
});
}
});
list->addItem(wifiMeteredToggle);
// Hidden Network
hiddenNetworkButton = new ButtonControl(tr("Hidden Network"), tr("CONNECT"));
@ -211,18 +233,32 @@ AdvancedNetworking::AdvancedNetworking(QWidget* parent, WifiManager* wifi): QWid
void AdvancedNetworking::setGsmVisible(bool visible) {
roamingToggle->setVisible(visible);
editApnButton->setVisible(visible);
meteredToggle->setVisible(visible);
cellularMeteredToggle->setVisible(visible);
}
void AdvancedNetworking::refresh() {
ipLabel->setText(wifi->ipv4_address);
tetheringToggle->setEnabled(true);
if (wifi->isTetheringEnabled() || wifi->ipv4_address == "") {
wifiMeteredToggle->setEnabled(false);
wifiMeteredToggle->setCheckedButton(0);
} else if (wifi->ipv4_address != "") {
MeteredType metered = wifi->currentNetworkMetered();
wifiMeteredToggle->setEnabled(true);
wifiMeteredToggle->setCheckedButton(static_cast<int>(metered));
}
update();
}
void AdvancedNetworking::toggleTethering(bool enabled) {
wifi->setTetheringEnabled(enabled);
tetheringToggle->setEnabled(false);
if (enabled) {
wifiMeteredToggle->setEnabled(false);
wifiMeteredToggle->setCheckedButton(0);
}
}
// WifiUI functions

@ -65,7 +65,8 @@ private:
ToggleControl* roamingToggle;
ButtonControl* editApnButton;
ButtonControl* hiddenNetworkButton;
ToggleControl* meteredToggle;
ToggleControl* cellularMeteredToggle;
MultiButtonControl* wifiMeteredToggle;
WifiManager* wifi = nullptr;
Params params;

@ -353,6 +353,7 @@ void WifiManager::activateModemConnection(const QDBusObjectPath &path) {
}
// function matches tici/hardware.py
// FIXME: it can mistakenly show CELL when connected to WIFI
NetworkType WifiManager::currentNetworkType() {
auto primary_conn = call<QDBusObjectPath>(NM_DBUS_PATH, NM_DBUS_INTERFACE_PROPERTIES, "Get", NM_DBUS_INTERFACE, "PrimaryConnection");
auto primary_type = call<QString>(primary_conn.path(), NM_DBUS_INTERFACE_PROPERTIES, "Get", NM_DBUS_INTERFACE_ACTIVE_CONNECTION, "Type");
@ -372,6 +373,44 @@ NetworkType WifiManager::currentNetworkType() {
return NetworkType::NONE;
}
MeteredType WifiManager::currentNetworkMetered() {
MeteredType metered = MeteredType::UNKNOWN;
for (const auto &active_conn : getActiveConnections()) {
QString type = call<QString>(active_conn.path(), NM_DBUS_INTERFACE_PROPERTIES, "Get", NM_DBUS_INTERFACE_ACTIVE_CONNECTION, "Type");
if (type == "802-11-wireless") {
QDBusObjectPath conn = call<QDBusObjectPath>(active_conn.path(), NM_DBUS_INTERFACE_PROPERTIES, "Get", NM_DBUS_INTERFACE_ACTIVE_CONNECTION, "Connection");
if (!conn.path().isEmpty()) {
Connection settings = getConnectionSettings(conn);
int metered_prop = settings.value("connection").value("metered").toInt();
if (metered_prop == NM_METERED_YES) {
metered = MeteredType::YES;
} else if (metered_prop == NM_METERED_NO) {
metered = MeteredType::NO;
}
}
break;
}
}
return metered;
}
std::optional<QDBusPendingCall> WifiManager::setCurrentNetworkMetered(MeteredType metered) {
for (const auto &active_conn : getActiveConnections()) {
QString type = call<QString>(active_conn.path(), NM_DBUS_INTERFACE_PROPERTIES, "Get", NM_DBUS_INTERFACE_ACTIVE_CONNECTION, "Type");
if (type == "802-11-wireless") {
if (!isTetheringEnabled()) {
QDBusObjectPath conn = call<QDBusObjectPath>(active_conn.path(), NM_DBUS_INTERFACE_PROPERTIES, "Get", NM_DBUS_INTERFACE_ACTIVE_CONNECTION, "Connection");
if (!conn.path().isEmpty()) {
Connection settings = getConnectionSettings(conn);
settings["connection"]["metered"] = static_cast<int>(metered);
return asyncCall(conn.path(), NM_DBUS_INTERFACE_SETTINGS_CONNECTION, "Update", QVariant::fromValue(settings));
}
}
}
}
return std::nullopt;
}
void WifiManager::updateGsmSettings(bool roaming, QString apn, bool metered) {
if (!lteConnectionPath.path().isEmpty()) {
bool changes = false;

@ -22,6 +22,11 @@ enum class NetworkType {
CELL,
ETHERNET
};
enum class MeteredType {
UNKNOWN,
YES,
NO
};
typedef QMap<QString, QVariantMap> Connection;
typedef QVector<QVariantMap> IpConfig;
@ -53,6 +58,8 @@ public:
bool isKnownConnection(const QString &ssid);
std::optional<QDBusPendingCall> activateWifiConnection(const QString &ssid);
NetworkType currentNetworkType();
MeteredType currentNetworkMetered();
std::optional<QDBusPendingCall> setCurrentNetworkMetered(MeteredType metered);
void updateGsmSettings(bool roaming, QString apn, bool metered);
void connect(const Network &ssid, const bool is_hidden = false, const QString &password = {}, const QString &username = {});

@ -204,6 +204,9 @@ public:
QPushButton:checked:enabled {
background-color: #33Ab4C;
}
QPushButton:checked:disabled {
background-color: #9933Ab4C;
}
QPushButton:disabled {
color: #33E4E4E4;
}
@ -214,6 +217,7 @@ public:
for (int i = 0; i < button_texts.size(); i++) {
QPushButton *button = new QPushButton(button_texts[i], this);
button->setCheckable(true);
button->setChecked(i == 0);
button->setStyleSheet(style);
button->setMinimumWidth(minimum_button_width);
hlayout->addWidget(button);

Loading…
Cancel
Save