mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-10-20 09:49:03 +02:00
Part of #21585 Android 17 apps need ACCESS_LOCAL_NETWORK to serve other devices on the LAN. The upload screen now asks for it when it opens, starts the web server once it's granted, and shows a warning and a retry button if it's denied. The permission only exists from API 37, so check for that rather than 35. On Android 15 and 16 it reads as denied, which left Remote ISO's connect tab stuck behind a permission request that could never succeed. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
118 lines
4.1 KiB
C++
118 lines
4.1 KiB
C++
#include <cmath>
|
|
#include "Common/Net/Resolve.h"
|
|
#include "Common/System/Request.h"
|
|
#include "Common/File/DiskFree.h"
|
|
#include "Common/StringUtils.h"
|
|
#include "Common/Data/Text/Parsers.h"
|
|
#include "Common/Data/Text/I18n.h"
|
|
#include "Common/UI/Notice.h"
|
|
#include "Common/System/System.h"
|
|
#include "Core/WebServer.h"
|
|
#include "Core/Util/PathUtil.h"
|
|
#include "UI/UploadScreen.h"
|
|
#include "UI/MiscViews.h"
|
|
|
|
UploadScreen::UploadScreen(const Path &targetFolder) : UISimpleBaseDialogScreen(Path(), SimpleDialogFlags::Default), targetFolder_(targetFolder) {
|
|
std::vector<std::string> ips;
|
|
net::GetLocalIP4List(ips);
|
|
localIPs_.clear();
|
|
for (const auto &ip : ips) {
|
|
if (!ip.empty() && !startsWith(ip, "127.") && !startsWith(ip, "169.254.")) {
|
|
localIPs_.push_back(ip);
|
|
}
|
|
}
|
|
// On Android 17+, serving to other devices on the local network needs a runtime permission.
|
|
prevPermission_ = System_GetPermissionStatus(SYSTEM_PERMISSION_LOCAL_NETWORK);
|
|
if (prevPermission_ != PERMISSION_STATUS_GRANTED) {
|
|
System_AskForPermission(SYSTEM_PERMISSION_LOCAL_NETWORK);
|
|
}
|
|
StartServerIfPermitted();
|
|
}
|
|
|
|
UploadScreen::~UploadScreen() {
|
|
if (started_) {
|
|
StopWebServer(WebServerFlags::FILE_UPLOAD);
|
|
}
|
|
}
|
|
|
|
void UploadScreen::StartServerIfPermitted() {
|
|
if (started_ || System_GetPermissionStatus(SYSTEM_PERMISSION_LOCAL_NETWORK) != PERMISSION_STATUS_GRANTED) {
|
|
return;
|
|
}
|
|
WebServerSetUploadPath(targetFolder_);
|
|
StartWebServer(WebServerFlags::FILE_UPLOAD);
|
|
started_ = true;
|
|
}
|
|
|
|
void UploadScreen::CreateDialogViews(UI::ViewGroup *root) {
|
|
using namespace UI;
|
|
auto n = GetI18NCategory(I18NCat::NETWORKING);
|
|
|
|
LinearLayout *container = new LinearLayout(ORIENT_VERTICAL, new LinearLayoutParams(500, FILL_PARENT, 0.0f, UI::Gravity::G_HCENTER, Margins(10)));
|
|
root->Add(container);
|
|
|
|
container->Add(new TextWithImage(ImageID("I_FOLDER_UPLOAD"), GetFriendlyPath(targetFolder_)));
|
|
container->Add(new Spacer(20.0f));
|
|
|
|
if (prevPermission_ == PERMISSION_STATUS_DENIED) {
|
|
container->Add(new NoticeView(NoticeLevel::WARN, n->T("Local network permission is needed to receive files"), ""))->SetWrapText(true);
|
|
container->Add(new Choice(n->T("Ask for network permission")))->OnClick.Add([](UI::EventParams &e) {
|
|
System_AskForPermission(SYSTEM_PERMISSION_LOCAL_NETWORK);
|
|
});
|
|
} else if (prevRunning_) {
|
|
container->Add(new TextWithImage(ImageID("I_WIFI"), n->T("With a web browser on the same network, go to:")));
|
|
for (const auto &ip : localIPs_) {
|
|
std::string url = StringFromFormat("%s:%d/upload", ip.c_str(), WebServerPort());
|
|
container->Add(new CopyableText(ImageID("I_WEB_BROWSER"), url));
|
|
}
|
|
}
|
|
|
|
statusContainer_ = new LinearLayout(ORIENT_VERTICAL);
|
|
container->Add(statusContainer_);
|
|
}
|
|
|
|
void UploadScreen::RecreateStatus() {
|
|
if (!statusContainer_) {
|
|
return;
|
|
}
|
|
|
|
using namespace UI;
|
|
statusContainer_->Clear();
|
|
// Show information about current upload streams (there can be multiple, but normally it's just one
|
|
// where files are uploaded sequentially).
|
|
std::vector<UploadProgress> uploads = GetUploadsInProgress();
|
|
for (const auto &upload : uploads) {
|
|
int percent = upload.totalBytes == 0 ? 0 : (int)(ceil(100.0 * (double)upload.uploadedBytes / (double)upload.totalBytes));
|
|
std::string uploadText = StringFromFormat("%s: %s/%s (%d%%)", upload.filename.c_str(),
|
|
NiceSizeFormat(upload.uploadedBytes).c_str(), NiceSizeFormat(upload.totalBytes).c_str(), percent);
|
|
statusContainer_->Add(new TextWithImage(ImageID("I_FILE"), uploadText));
|
|
}
|
|
}
|
|
|
|
std::string_view UploadScreen::GetTitle() const {
|
|
auto n = GetI18NCategory(I18NCat::NETWORKING);
|
|
return n->T("Upload files");
|
|
}
|
|
|
|
void UploadScreen::update() {
|
|
UISimpleBaseDialogScreen::update();
|
|
PermissionStatus permission = System_GetPermissionStatus(SYSTEM_PERMISSION_LOCAL_NETWORK);
|
|
if (permission != prevPermission_) {
|
|
prevPermission_ = permission;
|
|
StartServerIfPermitted();
|
|
RecreateViews();
|
|
}
|
|
|
|
bool running = WebServerRunning(WebServerFlags::FILE_UPLOAD);
|
|
if (prevRunning_ != running) {
|
|
prevRunning_ = running;
|
|
RecreateViews();
|
|
}
|
|
|
|
// Update in-progress uploads approximately every quarter of a second.
|
|
if (lastUpdate_.ElapsedSeconds() > 0.25) {
|
|
RecreateStatus();
|
|
lastUpdate_ = Instant::Now();
|
|
}
|
|
}
|