diff --git a/CMakeLists.txt b/CMakeLists.txt
index b600fde43e..cfce950a01 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -640,6 +640,8 @@ add_library(native STATIC
native/util/random/rng.h
native/util/text/utf8.h
native/util/text/utf8.cpp
+ native/util/text/parsers.h
+ native/util/text/parsers.cpp
native/util/const_map.h
native/ext/jpge/jpgd.cpp
native/ext/jpge/jpgd.h
diff --git a/Core/Config.cpp b/Core/Config.cpp
index 8a4a63fd8b..e710c3f36f 100644
--- a/Core/Config.cpp
+++ b/Core/Config.cpp
@@ -17,15 +17,24 @@
#include "base/display.h"
#include "base/NativeApp.h"
+#include "ext/vjson/json.h"
+#include "file/ini_file.h"
+#include "i18n/i18n.h"
+#include "gfx_es2/gpu_features.h"
+#include "net/http_client.h"
+#include "util/text/parsers.h"
+
+#include "Common/CPUDetect.h"
#include "Common/KeyMap.h"
#include "Common/FileUtil.h"
#include "Common/StringUtils.h"
#include "Config.h"
-#include "file/ini_file.h"
-#include "i18n/i18n.h"
-#include "gfx_es2/gpu_features.h"
#include "HLE/sceUtility.h"
-#include "Common/CPUDetect.h"
+
+extern const char *PPSSPP_GIT_VERSION;
+
+// TODO: Find a better place for this.
+http::Downloader g_DownloadManager;
Config g_Config;
@@ -325,6 +334,24 @@ void Config::Load(const char *iniFileName, const char *controllerIniFilename) {
IniFile::Section *jitConfig = iniFile.GetOrCreateSection("JIT");
jitConfig->Get("DiscardRegsOnJRRA", &bDiscardRegsOnJRRA, false);
+ IniFile::Section *upgrade = iniFile.GetOrCreateSection("Upgrade");
+ upgrade->Get("UpgradeMessage", &upgradeMessage, "");
+ upgrade->Get("UpgradeVersion", &upgradeVersion, "");
+ upgrade->Get("DismissedVersion", &dismissedVersion, "");
+
+ if (dismissedVersion == upgradeVersion) {
+ upgradeMessage = "";
+ }
+
+ // Check for new version on every 5 runs.
+ // Sometimes the download may not be finished when the main screen shows (if the user dismisses the
+ // splash screen quickly), but then we'll just show the notification next time instead, we store the
+ // upgrade number in the ini.
+ if (iRunCount % 5 == 0) {
+ g_DownloadManager.StartDownloadWithCallback(
+ "http://www.ppsspp.org/version.json", "", &DownloadCompletedCallback);
+ }
+
INFO_LOG(LOADER, "Loading controller config: %s", controllerIniFilename_.c_str());
bSaveSettings = true;
@@ -528,6 +555,12 @@ void Config::Save() {
speedhacks->Set("PrescaleUV", bPrescaleUV);
speedhacks->Set("DisableAlphaTest", bDisableAlphaTest);
+ // Save upgrade check state
+ IniFile::Section *upgrade = iniFile.GetOrCreateSection("Upgrade");
+ upgrade->Set("UpgradeMessage", upgradeMessage);
+ upgrade->Set("UpgradeVersion", upgradeVersion);
+ upgrade->Set("DismissedVersion", dismissedVersion);
+
if (!iniFile.Save(iniFilename_.c_str())) {
ERROR_LOG(LOADER, "Error saving config - can't write ini %s", iniFilename_.c_str());
return;
@@ -551,6 +584,54 @@ void Config::Save() {
}
}
+// Use for debugging the version check without messing with the server
+#if 0
+#define PPSSPP_GIT_VERSION "v0.0.1-gaaaaaaaaa"
+#endif
+
+void Config::DownloadCompletedCallback(http::Download &download) {
+ if (download.ResultCode() != 200) {
+ ERROR_LOG(LOADER, "Failed to download version.json");
+ }
+ std::string data;
+ download.buffer().TakeAll(&data);
+ JsonReader reader(data.c_str(), data.size());
+ const json_value *root = reader.root();
+ std::string version = root->getString("version", "");
+
+ const char *gitVer = PPSSPP_GIT_VERSION;
+ Version installed(gitVer);
+ Version upgrade(version);
+ Version dismissed(g_Config.dismissedVersion);
+
+ if (!installed.IsValid()) {
+ ERROR_LOG(LOADER, "Version check: Local version string invalid. Build problems? %s", PPSSPP_GIT_VERSION);
+ return;
+ }
+ if (!upgrade.IsValid()) {
+ ERROR_LOG(LOADER, "Version check: Invalid server version: %s", version.c_str());
+ return;
+ }
+
+ if (installed >= upgrade) {
+ INFO_LOG(LOADER, "Version check: Already up to date, erasing any upgrade message");
+ g_Config.upgradeMessage = "";
+ g_Config.upgradeVersion = upgrade.ToString();
+ g_Config.dismissedVersion = "";
+ return;
+ }
+
+ if (installed < upgrade && dismissed != upgrade) {
+ g_Config.upgradeMessage = "New version of PPSSPP available!";
+ g_Config.upgradeVersion = upgrade.ToString();
+ g_Config.dismissedVersion = "";
+ }
+}
+
+void Config::DismissUpgrade() {
+ g_Config.dismissedVersion = g_Config.upgradeVersion;
+}
+
void Config::AddRecent(const std::string &file) {
for (auto str = recentIsos.begin(); str != recentIsos.end(); ++str) {
#ifdef _WIN32
diff --git a/Core/Config.h b/Core/Config.h
index f0130e9e64..1ede569d58 100644
--- a/Core/Config.h
+++ b/Core/Config.h
@@ -28,6 +28,11 @@ extern const char *PPSSPP_GIT_VERSION;
const int MAX_CONFIG_VOLUME = 8;
+namespace http {
+ class Download;
+ class Downloader;
+}
+
struct Config {
public:
Config();
@@ -238,6 +243,11 @@ public:
std::string flash0Directory;
std::string internalDataDirectory;
+ // Data for upgrade prompt
+ std::string upgradeMessage; // The actual message from the server is currently not used, need a translation mechanism. So this just acts as a flag.
+ std::string upgradeVersion;
+ std::string dismissedVersion;
+
void Load(const char *iniFileName = "ppsspp.ini", const char *controllerIniFilename = "controls.ini");
void Save();
void RestoreDefaults();
@@ -252,6 +262,9 @@ public:
void AddRecent(const std::string &file);
void CleanRecent();
+ static void DownloadCompletedCallback(http::Download &download);
+ void DismissUpgrade();
+
private:
std::string iniFilename_;
std::string controllerIniFilename_;
@@ -259,4 +272,7 @@ private:
std::string defaultPath_;
};
+// TODO: Find a better place for this.
+extern http::Downloader g_DownloadManager;
extern Config g_Config;
+
diff --git a/Qt/Native.pro b/Qt/Native.pro
index fcc1a056c0..b46b7a5f20 100755
--- a/Qt/Native.pro
+++ b/Qt/Native.pro
@@ -90,7 +90,8 @@ SOURCES += $$P/native/audio/*.cpp \
$$P/native/util/bits/*.cpp \
$$P/native/util/hash/hash.cpp \
$$P/native/util/random/perlin.cpp \
- $$P/native/util/text/utf8.cpp
+ $$P/native/util/text/utf8.cpp \
+ $$P/native/util/text/parsers.cpp
HEADERS += $$P/native/audio/*.h \
$$P/native/base/basictypes.h \
@@ -123,6 +124,7 @@ HEADERS += $$P/native/audio/*.h \
$$P/native/util/bits/*.h \
$$P/native/util/hash/hash.h \
$$P/native/util/random/*.h \
- $$P/native/util/text/utf8.h
+ $$P/native/util/text/utf8.h \
+ $$P/native/util/text/parsers.h
INCLUDEPATH += $$P/native
diff --git a/UI/MainScreen.cpp b/UI/MainScreen.cpp
index 299f5836ab..5806a646a5 100644
--- a/UI/MainScreen.cpp
+++ b/UI/MainScreen.cpp
@@ -480,6 +480,7 @@ void MainScreen::CreateViews() {
gold->SetIcon(I_ICONGOLD);
#endif
rightColumnItems->Add(new Choice(m->T("Exit")))->OnClick.Handle(this, &MainScreen::OnExit);
+
if (vertical) {
root_ = new LinearLayout(ORIENT_VERTICAL);
rightColumn->ReplaceLayoutParams(new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT));
@@ -493,6 +494,49 @@ void MainScreen::CreateViews() {
root_->Add(leftColumn);
root_->Add(rightColumn);
}
+
+ I18NCategory *u = GetI18NCategory("Upgrade");
+
+ upgradeBar_ = 0;
+ if (!g_Config.upgradeMessage.empty()) {
+ upgradeBar_ = new LinearLayout(ORIENT_HORIZONTAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT));
+
+ UI::Margins textMargins(10, 5);
+ UI::Margins buttonMargins(0, 0);
+ UI::Drawable solid(0xFFbd9939);
+ upgradeBar_->SetBG(solid);
+ upgradeBar_->Add(new TextView(u->T("New version of PPSSPP available") + std::string(": ") + g_Config.upgradeVersion, new LinearLayoutParams(1.0f, textMargins)));
+ upgradeBar_->Add(new Button(u->T("Download"), new LinearLayoutParams(buttonMargins)))->OnClick.Handle(this, &MainScreen::OnDownloadUpgrade);
+ upgradeBar_->Add(new Button(u->T("Dismiss"), new LinearLayoutParams(buttonMargins)))->OnClick.Handle(this, &MainScreen::OnDismissUpgrade);
+
+ // Slip in under root_
+ LinearLayout *newRoot = new LinearLayout(ORIENT_VERTICAL);
+ newRoot->Add(root_);
+ newRoot->Add(upgradeBar_);
+ root_->ReplaceLayoutParams(new LinearLayoutParams(1.0));
+ root_ = newRoot;
+ }
+}
+
+UI::EventReturn MainScreen::OnDownloadUpgrade(UI::EventParams &e) {
+#ifdef ANDROID
+ // Go to app store
+#ifdef GOLD
+ LaunchBrowser("market://details?id=org.ppsspp.ppssppgold");
+#else
+ LaunchBrowser("market://details?id=org.ppsspp.ppsspp");
+#endif
+#else
+ // Go directly to ppsspp.org and let the user sort it out
+ LaunchBrowser("http://www.ppsspp.org/downloads.html");
+#endif
+ return EVENT_DONE;
+}
+
+UI::EventReturn MainScreen::OnDismissUpgrade(UI::EventParams &e) {
+ g_Config.DismissUpgrade();
+ upgradeBar_->SetVisibility(V_GONE);
+ return EVENT_DONE;
}
void MainScreen::sendMessage(const char *message, const char *value) {
diff --git a/UI/MainScreen.h b/UI/MainScreen.h
index 49de1b45b0..308f86473c 100644
--- a/UI/MainScreen.h
+++ b/UI/MainScreen.h
@@ -49,6 +49,10 @@ private:
UI::EventReturn OnPPSSPPOrg(UI::EventParams &e);
UI::EventReturn OnForums(UI::EventParams &e);
UI::EventReturn OnExit(UI::EventParams &e);
+ UI::EventReturn OnDownloadUpgrade(UI::EventParams &e);
+ UI::EventReturn OnDismissUpgrade(UI::EventParams &e);
+
+ UI::LinearLayout *upgradeBar_;
};
class GamePauseScreen : public UIDialogScreen {
diff --git a/UI/NativeApp.cpp b/UI/NativeApp.cpp
index 436825376b..f1b31ee9c5 100644
--- a/UI/NativeApp.cpp
+++ b/UI/NativeApp.cpp
@@ -34,10 +34,10 @@
#include "base/NativeApp.h"
#include "file/vfs.h"
#include "file/zip_read.h"
-#include "native/ext/stb_image_write/stb_image_writer.h"
-#include "native/ext/jpge/jpge.h"
-#include "native/util/text/utf8.h"
-#include "native/thread/thread.h"
+#include "ext/stb_image_write/stb_image_writer.h"
+#include "ext/jpge/jpge.h"
+#include "thread/thread.h"
+#include "net/http_client.h"
#include "gfx_es2/gl_state.h"
#include "gfx_es2/draw_text.h"
#include "gfx_es2/draw_buffer.h"
@@ -51,6 +51,7 @@
#include "ui/screen.h"
#include "ui/ui_context.h"
#include "ui/view.h"
+#include "util/text/utf8.h"
#include "Common/FileUtil.h"
#include "Common/LogManager.h"
@@ -598,6 +599,7 @@ void NativeUpdate(InputState &input) {
}
}
+ g_DownloadManager.Update();
screenManager->update(input);
}
diff --git a/Windows/PPSSPP.sln b/Windows/PPSSPP.sln
index cd12576b10..d589d3d501 100644
--- a/Windows/PPSSPP.sln
+++ b/Windows/PPSSPP.sln
@@ -32,6 +32,9 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Core", "..\Core\Core.vcxpro
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "native", "..\native\native.vcxproj", "{C4DF647E-80EA-4111-A0A8-218B1B711E18}"
+ ProjectSection(ProjectDependencies) = postProject
+ {F761046E-6C38-4428-A5F1-38391A37BB34} = {F761046E-6C38-4428-A5F1-38391A37BB34}
+ EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PPSSPPHeadless", "..\headless\Headless.vcxproj", "{EE9BD869-CAA3-447D-8328-294D90DE2C1F}"
ProjectSection(ProjectDependencies) = postProject
@@ -46,6 +49,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libkirk", "..\ext\libkirk\l
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "UnitTest", "..\unittest\UnitTests.vcxproj", "{37CBC214-7CE7-4655-B619-F7CEE16E3313}"
ProjectSection(ProjectDependencies) = postProject
+ {F761046E-6C38-4428-A5F1-38391A37BB34} = {F761046E-6C38-4428-A5F1-38391A37BB34}
{C4DF647E-80EA-4111-A0A8-218B1B711E18} = {C4DF647E-80EA-4111-A0A8-218B1B711E18}
EndProjectSection
EndProject
diff --git a/native b/native
index 3bb995319b..d2e70ce06f 160000
--- a/native
+++ b/native
@@ -1 +1 @@
-Subproject commit 3bb995319bc6142e93a066edb0d864033b51e0cc
+Subproject commit d2e70ce06fd54e0c884afe8d8b876ae28ce16df0
diff --git a/unittest/UnitTests.vcxproj b/unittest/UnitTests.vcxproj
index 0ef1bb9656..0f30f866e9 100644
--- a/unittest/UnitTests.vcxproj
+++ b/unittest/UnitTests.vcxproj
@@ -170,6 +170,9 @@
{533f1d30-d04d-47cc-ad71-20f658907e36}
+
+ {f761046e-6c38-4428-a5f1-38391a37bb34}
+
{c4df647e-80ea-4111-a0a8-218b1b711e18}