@@ -124,17 +124,20 @@ public InputOverlay(Context context, AttributeSet attrs)
if (!mPreferences.getBoolean("OverlayInitV3", false))
defaultOverlay();

// Load the controls.
if (NativeLibrary.IsRunning())
// Load the controls if we can. If not, EmulationActivity has to do it later.
if (NativeLibrary.IsGameMetadataValid())
{
// We would've needed a refreshControls call here in addition to the initTouchPointer call
// if it wasn't for initTouchPointer calling refreshControls.
initTouchPointer();
}
else
{
// We can't call initTouchPointer yet because it needs the aspect ratio of the running game.
refreshControls();
if (NativeLibrary.IsRunning())
{
// We would've needed a refreshControls call here in addition to the initTouchPointer call
// if it wasn't for initTouchPointer calling refreshControls.
initTouchPointer();
}
else
{
// We can't call initTouchPointer yet because it needs the aspect ratio of the running game.
refreshControls();
}
}

// Set the on touch listener.
@@ -152,7 +155,7 @@ public void initTouchPointer()
// Refresh before starting the pointer
refreshControls();

if (!EmulationActivity.isGameCubeGame())
if (!NativeLibrary.IsEmulatingWii())
{
int doubleTapButton = IntSetting.MAIN_DOUBLE_TAP_BUTTON.getIntGlobal();

@@ -715,7 +718,7 @@ public void refreshControls()
if (BooleanSetting.MAIN_SHOW_INPUT_OVERLAY.getBooleanGlobal())
{
// Add all the enabled overlay items back to the HashSet.
if (EmulationActivity.isGameCubeGame())
if (!NativeLibrary.IsEmulatingWii())
{
IniFile dolphinIni = new IniFile(SettingsFile.getSettingsFile(Settings.FILE_DOLPHIN));

@@ -775,7 +778,7 @@ public void resetButtonPlacement()
getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE;

// Values for these come from R.array.controllersEntries
if (EmulationActivity.isGameCubeGame() || mPreferences.getInt("wiiController", 3) == 0)
if (!NativeLibrary.IsEmulatingWii() || mPreferences.getInt("wiiController", 3) == 0)
{
if (isLandscape)
gcDefaultOverlay();
@@ -86,6 +86,15 @@ public static GameFile findSecondDisc(GameFile game)
return matchWithoutRevision;
}

public static String[] findSecondDiscAndGetPaths(GameFile gameFile)
{
GameFile secondFile = findSecondDisc(gameFile);
if (secondFile == null)
return new String[]{gameFile.getPath()};
else
return new String[]{gameFile.getPath(), secondFile.getPath()};
}

public static boolean hasLoadedCache()
{
return hasLoadedCache.get();
@@ -201,7 +201,7 @@ protected void onActivityResult(int requestCode, int resultCode, Intent result)
break;

case MainPresenter.REQUEST_GAME_FILE:
EmulationActivity.launchFile(this, FileBrowserHelper.getSelectedFiles(result));
EmulationActivity.launch(this, FileBrowserHelper.getSelectedFiles(result));
break;

case MainPresenter.REQUEST_WAD_FILE:
@@ -142,7 +142,8 @@ void setupUI()
TvGameViewHolder holder = (TvGameViewHolder) itemViewHolder;

// Start the emulation activity and send the path of the clicked ISO to it.
EmulationActivity.launch(TvMainActivity.this, holder.gameFile);
String[] paths = GameFileCacheService.findSecondDiscAndGetPaths(holder.gameFile);
EmulationActivity.launch(TvMainActivity.this, paths);
}
});
}
@@ -224,7 +225,7 @@ protected void onActivityResult(int requestCode, int resultCode, Intent result)
break;

case MainPresenter.REQUEST_GAME_FILE:
EmulationActivity.launchFile(this, FileBrowserHelper.getSelectedFiles(result));
EmulationActivity.launch(this, FileBrowserHelper.getSelectedFiles(result));
break;

case MainPresenter.REQUEST_WAD_FILE:
@@ -48,7 +48,7 @@ public static void HandleInit(FragmentActivity parent)
if (start_files != null && start_files.length > 0)
{
// Start the emulation activity, send the ISO passed in and finish the main activity
EmulationActivity.launchFile(parent, start_files);
EmulationActivity.launch(parent, start_files);
parent.finish();
}
}
@@ -13,7 +13,8 @@ static JavaVM* s_java_vm;
static jclass s_native_library_class;
static jmethodID s_display_alert_msg;
static jmethodID s_do_rumble;
static jmethodID s_get_update_touch_pointer;
static jmethodID s_update_touch_pointer;
static jmethodID s_on_title_changed;

static jclass s_game_file_class;
static jfieldID s_game_file_pointer;
@@ -85,7 +86,12 @@ jmethodID GetDoRumble()

jmethodID GetUpdateTouchPointer()
{
return s_get_update_touch_pointer;
return s_update_touch_pointer;
}

jmethodID GetOnTitleChanged()
{
return s_on_title_changed;
}

jclass GetAnalyticsClass()
@@ -212,8 +218,9 @@ jint JNI_OnLoad(JavaVM* vm, void* reserved)
s_display_alert_msg = env->GetStaticMethodID(s_native_library_class, "displayAlertMsg",
"(Ljava/lang/String;Ljava/lang/String;ZZ)Z");
s_do_rumble = env->GetStaticMethodID(s_native_library_class, "rumble", "(ID)V");
s_get_update_touch_pointer =
s_update_touch_pointer =
env->GetStaticMethodID(s_native_library_class, "updateTouchPointer", "()V");
s_on_title_changed = env->GetStaticMethodID(s_native_library_class, "onTitleChanged", "()V");
env->DeleteLocalRef(native_library_class);

const jclass game_file_class = env->FindClass("org/dolphinemu/dolphinemu/model/GameFile");
@@ -16,6 +16,7 @@ jclass GetNativeLibraryClass();
jmethodID GetDisplayAlertMsg();
jmethodID GetDoRumble();
jmethodID GetUpdateTouchPointer();
jmethodID GetOnTitleChanged();

jclass GetAnalyticsClass();
jmethodID GetSendAnalyticsReport();
@@ -80,6 +80,7 @@ std::mutex s_host_identity_lock;
Common::Event s_update_main_frame_event;
Common::Event s_emulation_end_event;
bool s_have_wm_user_stop = false;
bool s_game_metadata_is_valid = false;
} // Anonymous namespace

void UpdatePointer()
@@ -149,6 +150,10 @@ void Host_YieldToUI()

void Host_TitleChanged()
{
s_game_metadata_is_valid = true;

JNIEnv* env = IDCache::GetEnvForThread();
env->CallStaticVoidMethod(IDCache::GetNativeLibraryClass(), IDCache::GetOnTitleChanged());
}

static bool MsgAlert(const char* caption, const char* text, bool yes_no, Common::MsgType style)
@@ -608,6 +613,7 @@ static void Run(JNIEnv* env, const std::vector<std::string>& paths,
}
}

s_game_metadata_is_valid = false;
Core::Shutdown();
ButtonManager::Shutdown();
guard.unlock();
@@ -752,6 +758,36 @@ JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SetObscuredP
OSD::SetObscuredPixelsTop(height);
}

JNIEXPORT jboolean JNICALL
Java_org_dolphinemu_dolphinemu_NativeLibrary_IsGameMetadataValid(JNIEnv* env, jobject obj)
{
return s_game_metadata_is_valid;
}

JNIEXPORT jboolean JNICALL
Java_org_dolphinemu_dolphinemu_NativeLibrary_IsEmulatingWiiUnchecked(JNIEnv* env, jobject obj)
{
return SConfig::GetInstance().bWii;
}

JNIEXPORT jstring JNICALL
Java_org_dolphinemu_dolphinemu_NativeLibrary_GetCurrentGameIDUnchecked(JNIEnv* env, jobject obj)
{
return ToJString(env, SConfig::GetInstance().GetGameID());
}

JNIEXPORT jstring JNICALL
Java_org_dolphinemu_dolphinemu_NativeLibrary_GetCurrentTitleDescriptionUnchecked(JNIEnv* env,
jobject obj)
{
// Prefer showing just the name. If no name is available, show just the game ID.
std::string description = SConfig::GetInstance().GetTitleName();
if (description.empty())
description = SConfig::GetInstance().GetTitleDescription();

return ToJString(env, description);
}

#ifdef __cplusplus
}
#endif
@@ -583,6 +583,11 @@ if (APPLE)
${IOB_LIBRARY}
${IOK_LIBRARY}
)
elseif (ANDROID)
target_link_libraries(core
PRIVATE
androidcommon
)
endif()

if(LIBUSB_FOUND)
@@ -681,12 +681,14 @@ void SConfig::SetRunningGameMetadata(const std::string& game_id, const std::stri

if (game_id == "00000000")
{
m_title_name.clear();
m_title_description.clear();
return;
}

const Core::TitleDatabase title_database;
const DiscIO::Language language = GetLanguageAdjustedForRegion(bWii, region);
m_title_name = title_database.GetTitleName(m_gametdb_id, language);
m_title_description = title_database.Describe(m_gametdb_id, language);
NOTICE_LOG(CORE, "Active title: %s", m_title_description.c_str());
Host_TitleChanged();
@@ -819,10 +821,10 @@ struct SetGameMetadata
SetGameMetadata(SConfig* config_, DiscIO::Region* region_) : config(config_), region(region_) {}
bool operator()(const BootParameters::Disc& disc) const
{
config->SetRunningGameMetadata(*disc.volume, disc.volume->GetGamePartition());
*region = disc.volume->GetRegion();
config->bWii = disc.volume->GetVolumeType() == DiscIO::Platform::WiiDisc;
config->m_disc_booted_from_game_list = true;
*region = disc.volume->GetRegion();
config->SetRunningGameMetadata(*disc.volume, disc.volume->GetGamePartition());
return true;
}

@@ -831,12 +833,14 @@ struct SetGameMetadata
if (!executable.reader->IsValid())
return false;

config->bWii = executable.reader->IsWii();

*region = DiscIO::Region::Unknown;
config->bWii = executable.reader->IsWii();

// Strip the .elf/.dol file extension and directories before the name
SplitPath(executable.path, nullptr, &config->m_debugger_game_id, nullptr);

Host_TitleChanged();

return true;
}

@@ -854,9 +858,10 @@ struct SetGameMetadata
}

const IOS::ES::TMDReader& tmd = wad.GetTMD();
config->SetRunningGameMetadata(tmd, DiscIO::Platform::WiiWAD);
config->bWii = true;
*region = tmd.GetRegion();
config->bWii = true;
config->SetRunningGameMetadata(tmd, DiscIO::Platform::WiiWAD);

return true;
}

@@ -869,16 +874,20 @@ struct SetGameMetadata
PanicAlertT("This title cannot be booted.");
return false;
}
config->SetRunningGameMetadata(tmd, DiscIO::Platform::WiiWAD);
config->bWii = true;

*region = tmd.GetRegion();
config->bWii = true;
config->SetRunningGameMetadata(tmd, DiscIO::Platform::WiiWAD);

return true;
}

bool operator()(const BootParameters::IPL& ipl) const
{
config->bWii = false;
*region = ipl.region;
config->bWii = false;
Host_TitleChanged();

return true;
}

@@ -888,8 +897,10 @@ struct SetGameMetadata
if (!dff_file)
return false;

config->bWii = dff_file->GetIsWii();
*region = DiscIO::Region::NTSC_U;
config->bWii = dff_file->GetIsWii();
Host_TitleChanged();

return true;
}

@@ -188,6 +188,7 @@ struct SConfig
bool m_disc_booted_from_game_list = false;

const std::string& GetGameID() const { return m_game_id; }
const std::string& GetTitleName() const { return m_title_name; }
const std::string& GetTitleDescription() const { return m_title_description; }
u64 GetTitleID() const { return m_title_id; }
u16 GetRevision() const { return m_revision; }
@@ -360,6 +361,7 @@ struct SConfig

std::string m_game_id;
std::string m_gametdb_id;
std::string m_title_name;
std::string m_title_description;
u64 m_title_id;
u16 m_revision;
@@ -85,6 +85,10 @@
#include "VideoCommon/VideoBackendBase.h"
#include "VideoCommon/VideoConfig.h"

#ifdef ANDROID
#include "jni/AndroidCommon/IDCache.h"
#endif

namespace Core
{
static bool s_wants_determinism;
@@ -335,6 +339,12 @@ static void CpuThread(const std::optional<std::string>& savestate_path, bool del
// This needs to be delayed until after the video backend is ready.
DolphinAnalytics::Instance().ReportGameStart();

#ifdef ANDROID
// For some reason, calling the JNI function AttachCurrentThread from the CPU thread after a
// certain point causes a crash if fastmem is enabled. Let's call it early to avoid that problem.
static_cast<void>(IDCache::GetEnvForThread());
#endif

if (_CoreParameter.bFastmem)
EMM::InstallExceptionHandler(); // Let's run under memory watch