mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-10-01 14:58:14 +00:00
Offer to install PSP firmware updaters instead of running them
Opening an official updater (a PSP/GAME/UPDATE EBOOT.PBP, identified by the MSTKUPDATE disc ID) from the main screen now brings up a confirmation dialog that unpacks the firmware into the NAND directory, where the emulated flash0/flash1 live. Running the updater itself doesn't work, so there was nothing useful to do with one before. Unpacks the file list for the model we claim to be (iPSPModel), on a worker thread, with a progress bar - for which PSARUnpackOptions gets an optional progress callback. AGENTS.md: translate UI strings last, in a separate commit The English string is what all ~47 languages get derived from, so rewording it after the sweep means redoing the sweep. Check the wording first. Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
1 parent
c989c2553e
commit
4b761f0715
12 files changed
+333
-1
No files matched your search
@@ -184,6 +184,11 @@ For string sanitation, we already have SanitizeString in StringUtils.cpp - add n
|
||||
|
||||
## Translated UI strings (assets/lang)
|
||||
|
||||
**When implementing new UI, translations come last, in their own commit after everything else is
|
||||
done.** Write the English strings, get the feature built and working, commit that - then stop and ask
|
||||
the user to check the English wording before translating anything. The English string is what all ~47
|
||||
languages get derived from, so rewording it afterwards means redoing the whole sweep.
|
||||
|
||||
One .ini file per language, keyed by section and key against `assets/lang/en_US.ini`. **Don't hand-edit
|
||||
the ~47 files**, and don't run the AI commands in `Tools/langtool` either - you can read the call site,
|
||||
which its fixed prompt can't. Do the translating yourself and let the tool do the file surgery. Run it
|
||||
|
||||
@@ -489,6 +489,9 @@ public:
|
||||
PSARCompression entryCompression() const { return entryCompression_; }
|
||||
// Empty for a directory, or for an entry we couldn't decompress.
|
||||
const std::vector<u8> &entryData() const { return entryData_; }
|
||||
// How far into the archive the next record starts, and where the records stop - i.e. progress.
|
||||
u32 position() const { return pos_; }
|
||||
size_t limit() const { return limit_; }
|
||||
|
||||
private:
|
||||
// Decrypts one record into 'out'. Returns the decrypted size, or <= 0 on failure.
|
||||
@@ -726,6 +729,10 @@ bool UnpackPSAR(const u8 *psar, size_t psarSize, const Path &outputDir, const PS
|
||||
stats->entries++;
|
||||
stats->compressionCounts[(int)reader.entryCompression()]++;
|
||||
|
||||
if (options.progress && reader.limit() > 0) {
|
||||
options.progress(std::min(1.0f, (float)reader.position() / (float)reader.limit()));
|
||||
}
|
||||
|
||||
if (options.verbose) {
|
||||
INFO_LOG(Log::Loader, "PSAR entry '%s' (%s, %d bytes)", reader.entryName().c_str(),
|
||||
PSARCompressionToString(reader.entryCompression()), (int)reader.entryData().size());
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <ctime>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
@@ -81,6 +82,9 @@ struct PSARUnpackOptions {
|
||||
bool listOnly = false;
|
||||
// Log a line per entry. Off by default - an updater holds well over a thousand of them.
|
||||
bool verbose = false;
|
||||
// Called on the unpacking thread after every entry, with how far through the archive we are
|
||||
// (0.0 to 1.0). Unpacking a full firmware takes a while, so a UI wants this.
|
||||
std::function<void(float)> progress;
|
||||
};
|
||||
|
||||
struct PSARUnpackStats {
|
||||
|
||||
@@ -99,6 +99,8 @@ list(APPEND UISource
|
||||
UploadScreen.cpp
|
||||
CwCheatScreen.h
|
||||
CwCheatScreen.cpp
|
||||
InstallUpdateScreen.h
|
||||
InstallUpdateScreen.cpp
|
||||
InstallZipScreen.h
|
||||
InstallZipScreen.cpp
|
||||
JitCompareScreen.h
|
||||
|
||||
@@ -0,0 +1,200 @@
|
||||
// Copyright (c) 2026- PPSSPP Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0 or later versions.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official git repository and contact information can be found at
|
||||
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
||||
|
||||
#include "Common/Data/Text/I18n.h"
|
||||
#include "Common/Data/Text/Parsers.h"
|
||||
#include "Common/File/DirListing.h"
|
||||
#include "Common/File/FileUtil.h"
|
||||
#include "Common/Log.h"
|
||||
#include "Common/StringUtils.h"
|
||||
#include "Common/Thread/Promise.h"
|
||||
#include "Common/Thread/ThreadManager.h"
|
||||
#include "Common/UI/UI.h"
|
||||
#include "Common/UI/View.h"
|
||||
#include "Common/UI/ViewGroup.h"
|
||||
|
||||
#include "Core/Config.h"
|
||||
#include "Core/ConfigValues.h"
|
||||
#include "Core/Util/PathUtil.h"
|
||||
|
||||
#include "UI/InstallUpdateScreen.h"
|
||||
#include "UI/MiscViews.h"
|
||||
|
||||
// An updater carries one file list per hardware revision, and anything the chosen model's list
|
||||
// doesn't name isn't part of its firmware. Unpacking the model we claim to be keeps flash0
|
||||
// consistent with what the emulator reports to games.
|
||||
static PSPModelGeneration EmulatedModelGeneration() {
|
||||
return g_Config.iPSPModel == PSP_MODEL_FAT ? PSPModelGeneration::PSP_1000 : PSPModelGeneration::PSP_2000;
|
||||
}
|
||||
|
||||
InstallUpdateScreen::InstallUpdateScreen(const Path &path, std::string_view title)
|
||||
: UISimpleBaseDialogScreen(Path(), SimpleDialogFlags::ContentsCanScroll), path_(path), title_(title) {
|
||||
destination_ = GetSysDirectory(DIRECTORY_NAND);
|
||||
|
||||
File::FileInfo fileInfo;
|
||||
if (File::GetFileInfo(path_, &fileInfo)) {
|
||||
fileSize_ = fileInfo.size;
|
||||
}
|
||||
// There's no practical way to merge two firmwares, so an install replaces whatever is there.
|
||||
overwrites_ = File::Exists(destination_ / "flash0");
|
||||
}
|
||||
|
||||
std::string_view InstallUpdateScreen::GetTitle() const {
|
||||
auto iz = GetI18NCategory(I18NCat::INSTALLZIP);
|
||||
return iz->T("PSP firmware update");
|
||||
}
|
||||
|
||||
void InstallUpdateScreen::CreateDialogViews(UI::ViewGroup *parent) {
|
||||
using namespace UI;
|
||||
|
||||
auto di = GetI18NCategory(I18NCat::DIALOG);
|
||||
auto iz = GetI18NCategory(I18NCat::INSTALLZIP);
|
||||
auto st = GetI18NCategory(I18NCat::STORE); // Borrow "Size" from here, like GameScreen does.
|
||||
|
||||
LinearLayout *container = parent->Add(new LinearLayout(ORIENT_VERTICAL, new LinearLayoutParams(600, WRAP_CONTENT, 0.0f, UI::Gravity::G_HCENTER, Margins(10))));
|
||||
|
||||
container->Add(new TextView(iz->T("Install PSP firmware update?"), ALIGN_LEFT, false))->SetBig(true);
|
||||
container->Add(new Spacer(8.0f));
|
||||
|
||||
if (!title_.empty()) {
|
||||
// The updater's own title, which spells out the firmware version.
|
||||
container->Add(new TextWithImage(ImageID("I_INFO"), title_));
|
||||
}
|
||||
container->Add(new TextWithImage(ImageID("I_FILE"), GetFriendlyPath(path_)));
|
||||
if (fileSize_ > 0) {
|
||||
container->Add(new TextView(StringFromFormat("%s: %s", st->T_cstr("Size"), NiceSizeFormat(fileSize_).c_str())));
|
||||
}
|
||||
|
||||
container->Add(new Spacer(12.0f));
|
||||
container->Add(new TextView(iz->T("Install into folder")));
|
||||
container->Add(new TextView(GetFriendlyPath(destination_)))->SetAlign(FLAG_WRAP_TEXT);
|
||||
|
||||
if (overwrites_) {
|
||||
container->Add(new NoticeView(NoticeLevel::WARN, di->T("Confirm Overwrite"), ""));
|
||||
}
|
||||
|
||||
container->Add(new Spacer(12.0f));
|
||||
|
||||
installChoice_ = container->Add(new Choice(iz->T("Install"), ImageID("I_FOLDER_UPLOAD")));
|
||||
installChoice_->OnClick.Add([this](UI::EventParams &e) {
|
||||
StartInstall();
|
||||
});
|
||||
|
||||
progressBar_ = container->Add(new ProgressBar());
|
||||
progressBar_->SetVisibility(V_GONE);
|
||||
|
||||
resultView_ = container->Add(new NoticeView(NoticeLevel::SUCCESS, "", ""));
|
||||
resultView_->SetVisibility(V_GONE);
|
||||
|
||||
// The screen can get recreated mid-install (a rotation, say), so pick the status back up.
|
||||
RefreshStatus();
|
||||
}
|
||||
|
||||
void InstallUpdateScreen::StartInstall() {
|
||||
if (state_ && !state_->done) {
|
||||
// Already running. A previous attempt that failed can be retried, though.
|
||||
return;
|
||||
}
|
||||
|
||||
state_ = std::make_shared<InstallState>();
|
||||
reportedDone_ = false;
|
||||
|
||||
PSARUnpackOptions options;
|
||||
options.model = EmulatedModelGeneration();
|
||||
|
||||
INFO_LOG(Log::Loader, "Unpacking the updater %s into %s (model %s)", path_.c_str(),
|
||||
destination_.c_str(), PSPModelGenerationToString(options.model));
|
||||
|
||||
g_threadManager.EnqueueTask(new IndependentTask(TaskType::IO_BLOCKING, TaskPriority::NORMAL,
|
||||
[state = state_, path = path_, destination = destination_, options]() mutable {
|
||||
options.progress = [state](float progress) {
|
||||
state->progress = progress;
|
||||
};
|
||||
state->success = UnpackUpdater(path, destination, options, &state->stats, &state->error);
|
||||
if (state->success && state->stats.written == 0) {
|
||||
// Nothing came out, so the archive had no file list for the model we asked for -
|
||||
// old firmwares predate the later models. Not something to call a success.
|
||||
state->success = false;
|
||||
if (state->error.empty()) {
|
||||
state->error = "The updater has no firmware for this PSP model";
|
||||
}
|
||||
}
|
||||
// Everything above is published by this store - see the atomic in InstallState.
|
||||
state->done = true;
|
||||
}));
|
||||
|
||||
RefreshStatus();
|
||||
}
|
||||
|
||||
void InstallUpdateScreen::RefreshStatus() {
|
||||
using namespace UI;
|
||||
|
||||
auto iz = GetI18NCategory(I18NCat::INSTALLZIP);
|
||||
|
||||
const bool installing = state_ && !state_->done;
|
||||
const bool succeeded = state_ && state_->done && state_->success;
|
||||
|
||||
if (installChoice_) {
|
||||
// There's no point installing the same firmware twice, but a failure can be retried.
|
||||
installChoice_->SetEnabled(!installing && !succeeded);
|
||||
}
|
||||
if (progressBar_) {
|
||||
progressBar_->SetVisibility(installing ? V_VISIBLE : V_GONE);
|
||||
if (installing) {
|
||||
progressBar_->SetProgress(state_->progress);
|
||||
}
|
||||
}
|
||||
if (resultView_) {
|
||||
if (!state_ || !state_->done) {
|
||||
resultView_->SetVisibility(V_GONE);
|
||||
} else if (state_->success) {
|
||||
resultView_->SetLevelAndText(NoticeLevel::SUCCESS, iz->T("Installed!"));
|
||||
resultView_->SetDetailsText(StringFromFormat("%s - %d files", state_->stats.firmwareVersion.c_str(), state_->stats.written));
|
||||
resultView_->SetVisibility(V_VISIBLE);
|
||||
} else {
|
||||
resultView_->SetLevelAndText(NoticeLevel::ERROR, iz->T("Installation failed"));
|
||||
resultView_->SetDetailsText(state_->error);
|
||||
resultView_->SetVisibility(V_VISIBLE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool InstallUpdateScreen::key(const KeyInput &key) {
|
||||
// Ignore key presses while installing, so the user can't escape out mid-write.
|
||||
if (state_ && !state_->done) {
|
||||
return false;
|
||||
}
|
||||
return UISimpleBaseDialogScreen::key(key);
|
||||
}
|
||||
|
||||
void InstallUpdateScreen::update() {
|
||||
UISimpleBaseDialogScreen::update();
|
||||
|
||||
if (!state_) {
|
||||
return;
|
||||
}
|
||||
if (state_->done && !reportedDone_) {
|
||||
reportedDone_ = true;
|
||||
if (state_->success) {
|
||||
INFO_LOG(Log::Loader, "Installed firmware %s: %d files, %d failed", state_->stats.firmwareVersion.c_str(),
|
||||
state_->stats.written, state_->stats.failed);
|
||||
} else {
|
||||
ERROR_LOG(Log::Loader, "Failed to install the updater: %s", state_->error.c_str());
|
||||
}
|
||||
}
|
||||
RefreshStatus();
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
// Copyright (c) 2026- PPSSPP Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0 or later versions.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official git repository and contact information can be found at
|
||||
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
#include "Common/File/Path.h"
|
||||
#include "Common/UI/Notice.h"
|
||||
#include "Common/UI/UIScreen.h"
|
||||
#include "Common/UI/View.h"
|
||||
#include "Common/UI/ViewGroup.h"
|
||||
|
||||
#include "Core/Util/PSARUnpack.h"
|
||||
|
||||
#include "UI/BaseScreens.h"
|
||||
#include "UI/SimpleDialogScreen.h"
|
||||
|
||||
// An official PSP firmware updater (a PSP/GAME/UPDATE/EBOOT.PBP, or the folder holding one).
|
||||
// Running it isn't going to get anyone anywhere, but the firmware inside it is exactly what the
|
||||
// emulated flash0/flash1 want, so offer to unpack it into the NAND directory instead.
|
||||
class InstallUpdateScreen : public UISimpleBaseDialogScreen {
|
||||
public:
|
||||
// title is the updater's SFO title, which already carries the version ("PSP Update ver 6.61").
|
||||
InstallUpdateScreen(const Path &path, std::string_view title);
|
||||
|
||||
void CreateDialogViews(UI::ViewGroup *parent) override;
|
||||
void update() override;
|
||||
bool key(const KeyInput &key) override;
|
||||
|
||||
const char *tag() const override { return "InstallUpdate"; }
|
||||
|
||||
protected:
|
||||
std::string_view GetTitle() const override;
|
||||
|
||||
private:
|
||||
// The unpack runs on a worker thread, and the user can leave the screen while it's going, so
|
||||
// the state it writes is shared with the task rather than owned by the screen.
|
||||
struct InstallState {
|
||||
std::atomic<float> progress{};
|
||||
std::atomic<bool> done{};
|
||||
// Only valid to read once done is set.
|
||||
bool success = false;
|
||||
PSARUnpackStats stats;
|
||||
std::string error;
|
||||
};
|
||||
|
||||
void StartInstall();
|
||||
void RefreshStatus();
|
||||
|
||||
Path path_;
|
||||
Path destination_;
|
||||
std::string title_;
|
||||
u64 fileSize_ = 0;
|
||||
bool overwrites_ = false;
|
||||
|
||||
std::shared_ptr<InstallState> state_;
|
||||
bool reportedDone_ = false;
|
||||
|
||||
UI::Choice *installChoice_ = nullptr;
|
||||
UI::ProgressBar *progressBar_ = nullptr;
|
||||
NoticeView *resultView_ = nullptr;
|
||||
};
|
||||
+18
-1
@@ -49,6 +49,7 @@
|
||||
#include "UI/RemoteISOScreen.h"
|
||||
#include "UI/DisplayLayoutScreen.h"
|
||||
#include "UI/SavedataScreen.h"
|
||||
#include "UI/InstallUpdateScreen.h"
|
||||
#include "UI/InstallZipScreen.h"
|
||||
#include "UI/Background.h"
|
||||
#include "UI/GameBrowser.h"
|
||||
@@ -68,7 +69,9 @@ static void LaunchFile(ScreenManager *screenManager, Screen *currentScreen, cons
|
||||
screenManager->push(new InstallZipScreen(path));
|
||||
} else {
|
||||
// Check if we already know that this game isn't playable.
|
||||
auto info = g_gameInfoCache->GetInfo(nullptr, path, GameInfoFlags::FILE_TYPE);
|
||||
// If coming from the main screen, the info will already be computed here since the icon is displayed etc.
|
||||
// Otherwise, we probably technically should wait for it...
|
||||
auto info = g_gameInfoCache->GetInfo(nullptr, path, GameInfoFlags::FILE_TYPE | GameInfoFlags::PARAM_SFO);
|
||||
|
||||
switch (info->fileType) {
|
||||
case IdentifiedFileType::PSP_UMD_VIDEO_ISO:
|
||||
@@ -82,6 +85,20 @@ static void LaunchFile(ScreenManager *screenManager, Screen *currentScreen, cons
|
||||
screenManager->push(new SavedataPopupScreen(Path(), path, title));
|
||||
return;
|
||||
}
|
||||
case IdentifiedFileType::PSP_PBP:
|
||||
case IdentifiedFileType::PSP_PBP_DIRECTORY:
|
||||
{
|
||||
// Check if it's an update file. If so, we'll offer to install it directly,
|
||||
// instead of running it (which currently will not work).
|
||||
if (info->id == "MSTKUPDATE") {
|
||||
std::string title = info->GetTitle(); // includes the version.
|
||||
// The unpacker wants the PBP itself, not the folder it happens to sit in.
|
||||
const Path pbpPath = info->fileType == IdentifiedFileType::PSP_PBP ? path : path / "EBOOT.PBP";
|
||||
screenManager->push(new InstallUpdateScreen(pbpPath, title));
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -79,6 +79,7 @@
|
||||
<ClCompile Include="TiltAnalogSettingsScreen.cpp" />
|
||||
<ClCompile Include="TouchControlLayoutScreen.cpp" />
|
||||
<ClCompile Include="TouchControlVisibilityScreen.cpp" />
|
||||
<ClCompile Include="InstallUpdateScreen.cpp" />
|
||||
<ClCompile Include="InstallZipScreen.cpp" />
|
||||
<ClCompile Include="Theme.cpp" />
|
||||
<ClCompile Include="UIAtlas.cpp" />
|
||||
@@ -136,6 +137,7 @@
|
||||
<ClInclude Include="TiltAnalogSettingsScreen.h" />
|
||||
<ClInclude Include="TouchControlLayoutScreen.h" />
|
||||
<ClInclude Include="TouchControlVisibilityScreen.h" />
|
||||
<ClInclude Include="InstallUpdateScreen.h" />
|
||||
<ClInclude Include="InstallZipScreen.h" />
|
||||
<ClInclude Include="Theme.h" />
|
||||
<ClInclude Include="UIAtlas.h" />
|
||||
|
||||
@@ -40,6 +40,9 @@
|
||||
<ClCompile Include="TiltAnalogSettingsScreen.cpp">
|
||||
<Filter>Screens</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="InstallUpdateScreen.cpp">
|
||||
<Filter>Screens</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="InstallZipScreen.cpp">
|
||||
<Filter>Screens</Filter>
|
||||
</ClCompile>
|
||||
@@ -191,6 +194,9 @@
|
||||
<ClInclude Include="TiltAnalogSettingsScreen.h">
|
||||
<Filter>Screens</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="InstallUpdateScreen.h">
|
||||
<Filter>Screens</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="InstallZipScreen.h">
|
||||
<Filter>Screens</Filter>
|
||||
</ClInclude>
|
||||
|
||||
@@ -114,6 +114,7 @@
|
||||
<ClInclude Include="..\..\UI\ImDebugger\ImJitViewer.h" />
|
||||
<ClInclude Include="..\..\UI\ImDebugger\ImMemView.h" />
|
||||
<ClInclude Include="..\..\UI\ImDebugger\ImStructViewer.h" />
|
||||
<ClInclude Include="..\..\UI\InstallUpdateScreen.h" />
|
||||
<ClInclude Include="..\..\UI\InstallZipScreen.h" />
|
||||
<ClInclude Include="..\..\UI\JitCompareScreen.h" />
|
||||
<ClInclude Include="..\..\UI\JoystickHistoryView.h" />
|
||||
@@ -172,6 +173,7 @@
|
||||
<ClCompile Include="..\..\UI\ImDebugger\ImJitViewer.cpp" />
|
||||
<ClCompile Include="..\..\UI\ImDebugger\ImMemView.cpp" />
|
||||
<ClCompile Include="..\..\UI\ImDebugger\ImStructViewer.cpp" />
|
||||
<ClCompile Include="..\..\UI\InstallUpdateScreen.cpp" />
|
||||
<ClCompile Include="..\..\UI\InstallZipScreen.cpp" />
|
||||
<ClCompile Include="..\..\UI\JitCompareScreen.cpp" />
|
||||
<ClCompile Include="..\..\UI\JoystickHistoryView.cpp" />
|
||||
|
||||
@@ -73,6 +73,9 @@
|
||||
<ClCompile Include="..\..\UI\IAPScreen.cpp">
|
||||
<Filter>Screens</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\UI\InstallUpdateScreen.cpp">
|
||||
<Filter>Screens</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\UI\InstallZipScreen.cpp">
|
||||
<Filter>Screens</Filter>
|
||||
</ClCompile>
|
||||
@@ -216,6 +219,9 @@
|
||||
<ClInclude Include="..\..\UI\IAPScreen.h">
|
||||
<Filter>Screens</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\UI\InstallUpdateScreen.h">
|
||||
<Filter>Screens</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\UI\InstallZipScreen.h">
|
||||
<Filter>Screens</Filter>
|
||||
</ClInclude>
|
||||
|
||||
@@ -984,6 +984,7 @@ LOCAL_SRC_FILES := \
|
||||
$(SRC)/UI/BaseScreens.cpp \
|
||||
$(SRC)/UI/Background.cpp \
|
||||
$(SRC)/UI/CwCheatScreen.cpp \
|
||||
$(SRC)/UI/InstallUpdateScreen.cpp \
|
||||
$(SRC)/UI/InstallZipScreen.cpp \
|
||||
$(SRC)/UI/JitCompareScreen.cpp \
|
||||
$(SRC)/UI/OnScreenDisplay.cpp \
|
||||
|
||||
Reference in new issue
Block a user