Merge pull request #9078 from JosJuice/android-metadata-from-core

Android: Get game metadata from core
This commit is contained in:
Léo Lam
2020-10-21 22:29:21 +02:00
committed by GitHub
17 changed files with 201 additions and 124 deletions

View File

@ -447,6 +447,40 @@ public final class NativeLibrary
public static native void SetObscuredPixelsTop(int height); public static native void SetObscuredPixelsTop(int height);
public static native boolean IsGameMetadataValid();
public static boolean IsEmulatingWii()
{
CheckGameMetadataValid();
return IsEmulatingWiiUnchecked();
}
public static String GetCurrentGameID()
{
CheckGameMetadataValid();
return GetCurrentGameIDUnchecked();
}
public static String GetCurrentTitleDescription()
{
CheckGameMetadataValid();
return GetCurrentTitleDescriptionUnchecked();
}
private static void CheckGameMetadataValid()
{
if (!IsGameMetadataValid())
{
throw new IllegalStateException("No game is running");
}
}
private static native boolean IsEmulatingWiiUnchecked();
private static native String GetCurrentGameIDUnchecked();
private static native String GetCurrentTitleDescriptionUnchecked();
public static boolean displayAlertMsg(final String caption, final String text, public static boolean displayAlertMsg(final String caption, final String text,
final boolean yesNo, final boolean isWarning) final boolean yesNo, final boolean isWarning)
{ {
@ -537,6 +571,19 @@ public final class NativeLibrary
} }
} }
private static void onTitleChanged()
{
final EmulationActivity emulationActivity = sEmulationActivity.get();
if (emulationActivity == null)
{
Log.warning("[NativeLibrary] EmulationActivity is null.");
}
else
{
emulationActivity.runOnUiThread(emulationActivity::onTitleChanged);
}
}
public static float getRenderSurfaceScale() public static float getRenderSurfaceScale()
{ {
DisplayMetrics metrics = new DisplayMetrics(); DisplayMetrics metrics = new DisplayMetrics();

View File

@ -139,6 +139,6 @@ public class AppLinkActivity extends FragmentActivity
mAfterDirectoryInitializationRunner.cancel(); mAfterDirectoryInitializationRunner.cancel();
mAfterDirectoryInitializationRunner = null; mAfterDirectoryInitializationRunner = null;
} }
EmulationActivity.launch(this, game); EmulationActivity.launch(this, GameFileCacheService.findSecondDiscAndGetPaths(game));
} }
} }

View File

@ -80,20 +80,13 @@ public final class EmulationActivity extends AppCompatActivity
private boolean mMenuVisible; private boolean mMenuVisible;
private static boolean sIgnoreLaunchRequests = false; private static boolean sIgnoreLaunchRequests = false;
private static boolean sIsGameCubeGame;
private boolean activityRecreated; private boolean activityRecreated;
private String mSelectedTitle;
private String mSelectedGameId;
private int mPlatform;
private String[] mPaths; private String[] mPaths;
private boolean mIgnoreWarnings; private boolean mIgnoreWarnings;
private static boolean sUserPausedEmulation; private static boolean sUserPausedEmulation;
public static final String EXTRA_SELECTED_GAMES = "SelectedGames"; public static final String EXTRA_SELECTED_GAMES = "SelectedGames";
public static final String EXTRA_SELECTED_TITLE = "SelectedTitle";
public static final String EXTRA_SELECTED_GAMEID = "SelectedGameId";
public static final String EXTRA_PLATFORM = "Platform";
public static final String EXTRA_IGNORE_WARNINGS = "IgnoreWarnings"; public static final String EXTRA_IGNORE_WARNINGS = "IgnoreWarnings";
public static final String EXTRA_USER_PAUSED_EMULATION = "sUserPausedEmulation"; public static final String EXTRA_USER_PAUSED_EMULATION = "sUserPausedEmulation";
@ -176,34 +169,7 @@ public final class EmulationActivity extends AppCompatActivity
EmulationActivity.MENU_ACTION_MOTION_CONTROLS); EmulationActivity.MENU_ACTION_MOTION_CONTROLS);
} }
private static String[] scanForSecondDisc(GameFile gameFile) public static void launch(FragmentActivity activity, String[] filePaths)
{
GameFile secondFile = GameFileCacheService.findSecondDisc(gameFile);
if (secondFile == null)
return new String[]{gameFile.getPath()};
else
return new String[]{gameFile.getPath(), secondFile.getPath()};
}
public static void launch(FragmentActivity activity, GameFile gameFile)
{
if (sIgnoreLaunchRequests)
return;
sIgnoreLaunchRequests = true;
Intent launcher = new Intent(activity, EmulationActivity.class);
launcher.putExtra(EXTRA_SELECTED_GAMES, scanForSecondDisc(gameFile));
launcher.putExtra(EXTRA_SELECTED_TITLE, gameFile.getTitle());
launcher.putExtra(EXTRA_SELECTED_GAMEID, gameFile.getGameId());
launcher.putExtra(EXTRA_PLATFORM, gameFile.getPlatform());
new AfterDirectoryInitializationRunner().run(activity, true,
() -> activity.startActivity(launcher));
}
public static void launchFile(FragmentActivity activity, String[] filePaths)
{ {
if (sIgnoreLaunchRequests) if (sIgnoreLaunchRequests)
return; return;
@ -213,30 +179,6 @@ public final class EmulationActivity extends AppCompatActivity
Intent launcher = new Intent(activity, EmulationActivity.class); Intent launcher = new Intent(activity, EmulationActivity.class);
launcher.putExtra(EXTRA_SELECTED_GAMES, filePaths); launcher.putExtra(EXTRA_SELECTED_GAMES, filePaths);
// Try parsing a GameFile first. This should succeed for disc images.
GameFile gameFile = GameFile.parse(filePaths[0]);
if (gameFile != null)
{
// We don't want to pollute the game file cache with this new file,
// so we can't just call launch() and let it handle the setup.
launcher.putExtra(EXTRA_SELECTED_TITLE, gameFile.getTitle());
launcher.putExtra(EXTRA_SELECTED_GAMEID, gameFile.getGameId());
launcher.putExtra(EXTRA_PLATFORM, gameFile.getPlatform());
}
else
{
// Display the path to the file as the game title in the menu.
launcher.putExtra(EXTRA_SELECTED_TITLE, filePaths[0]);
// Use 00000000 as the game ID. This should match the Desktop version behavior.
// TODO: This should really be pulled from the Core.
launcher.putExtra(EXTRA_SELECTED_GAMEID, "00000000");
// GameFile might be a FIFO log. Assume GameCube for the platform. It doesn't really matter
// anyway, since this only controls the input, and the FIFO player doesn't take any input.
launcher.putExtra(EXTRA_PLATFORM, Platform.GAMECUBE);
}
new AfterDirectoryInitializationRunner().run(activity, true, new AfterDirectoryInitializationRunner().run(activity, true,
() -> activity.startActivity(launcher)); () -> activity.startActivity(launcher));
} }
@ -272,9 +214,6 @@ public final class EmulationActivity extends AppCompatActivity
// Get params we were passed // Get params we were passed
Intent gameToEmulate = getIntent(); Intent gameToEmulate = getIntent();
mPaths = gameToEmulate.getStringArrayExtra(EXTRA_SELECTED_GAMES); mPaths = gameToEmulate.getStringArrayExtra(EXTRA_SELECTED_GAMES);
mSelectedTitle = gameToEmulate.getStringExtra(EXTRA_SELECTED_TITLE);
mSelectedGameId = gameToEmulate.getStringExtra(EXTRA_SELECTED_GAMEID);
mPlatform = gameToEmulate.getIntExtra(EXTRA_PLATFORM, 0);
mIgnoreWarnings = gameToEmulate.getBooleanExtra(EXTRA_IGNORE_WARNINGS, false); mIgnoreWarnings = gameToEmulate.getBooleanExtra(EXTRA_IGNORE_WARNINGS, false);
sUserPausedEmulation = gameToEmulate.getBooleanExtra(EXTRA_USER_PAUSED_EMULATION, false); sUserPausedEmulation = gameToEmulate.getBooleanExtra(EXTRA_USER_PAUSED_EMULATION, false);
activityRecreated = false; activityRecreated = false;
@ -293,9 +232,6 @@ public final class EmulationActivity extends AppCompatActivity
updateOrientation(); updateOrientation();
// TODO: The accurate way to find out which console we're emulating is to first
// launch emulation and then ask the core which console we're emulating
sIsGameCubeGame = Platform.fromNativeInt(mPlatform) == Platform.GAMECUBE;
mDeviceHasTouchScreen = getPackageManager().hasSystemFeature("android.hardware.touchscreen"); mDeviceHasTouchScreen = getPackageManager().hasSystemFeature("android.hardware.touchscreen");
mMotionListener = new MotionListener(this); mMotionListener = new MotionListener(this);
@ -317,7 +253,8 @@ public final class EmulationActivity extends AppCompatActivity
.commit(); .commit();
} }
setTitle(mSelectedTitle); if (NativeLibrary.IsGameMetadataValid())
setTitle(NativeLibrary.GetCurrentTitleDescription());
} }
@Override @Override
@ -329,9 +266,6 @@ public final class EmulationActivity extends AppCompatActivity
mEmulationFragment.saveTemporaryState(); mEmulationFragment.saveTemporaryState();
} }
outState.putStringArray(EXTRA_SELECTED_GAMES, mPaths); outState.putStringArray(EXTRA_SELECTED_GAMES, mPaths);
outState.putString(EXTRA_SELECTED_TITLE, mSelectedTitle);
outState.putString(EXTRA_SELECTED_GAMEID, mSelectedGameId);
outState.putInt(EXTRA_PLATFORM, mPlatform);
outState.putBoolean(EXTRA_USER_PAUSED_EMULATION, mIgnoreWarnings); outState.putBoolean(EXTRA_USER_PAUSED_EMULATION, mIgnoreWarnings);
outState.putBoolean(EXTRA_USER_PAUSED_EMULATION, sUserPausedEmulation); outState.putBoolean(EXTRA_USER_PAUSED_EMULATION, sUserPausedEmulation);
super.onSaveInstanceState(outState); super.onSaveInstanceState(outState);
@ -340,9 +274,6 @@ public final class EmulationActivity extends AppCompatActivity
protected void restoreState(Bundle savedInstanceState) protected void restoreState(Bundle savedInstanceState)
{ {
mPaths = savedInstanceState.getStringArray(EXTRA_SELECTED_GAMES); mPaths = savedInstanceState.getStringArray(EXTRA_SELECTED_GAMES);
mSelectedTitle = savedInstanceState.getString(EXTRA_SELECTED_TITLE);
mSelectedGameId = savedInstanceState.getString(EXTRA_SELECTED_GAMEID);
mPlatform = savedInstanceState.getInt(EXTRA_PLATFORM);
mIgnoreWarnings = savedInstanceState.getBoolean(EXTRA_IGNORE_WARNINGS); mIgnoreWarnings = savedInstanceState.getBoolean(EXTRA_IGNORE_WARNINGS);
sUserPausedEmulation = savedInstanceState.getBoolean(EXTRA_USER_PAUSED_EMULATION); sUserPausedEmulation = savedInstanceState.getBoolean(EXTRA_USER_PAUSED_EMULATION);
} }
@ -361,8 +292,8 @@ public final class EmulationActivity extends AppCompatActivity
{ {
super.onResume(); super.onResume();
if (!sIsGameCubeGame && IntSetting.MAIN_MOTION_CONTROLS.getInt(mSettings) != 2) if (NativeLibrary.IsGameMetadataValid())
mMotionListener.enable(); updateMotionListener();
} }
@Override @Override
@ -378,6 +309,23 @@ public final class EmulationActivity extends AppCompatActivity
super.onStop(); super.onStop();
} }
public void onTitleChanged()
{
setTitle(NativeLibrary.GetCurrentTitleDescription());
updateMotionListener();
if (mDeviceHasTouchScreen)
mEmulationFragment.refreshInputOverlay();
}
private void updateMotionListener()
{
if (NativeLibrary.IsEmulatingWii() && IntSetting.MAIN_MOTION_CONTROLS.getInt(mSettings) != 2)
mMotionListener.enable();
else
mMotionListener.disable();
}
@Override @Override
protected void onDestroy() protected void onDestroy()
{ {
@ -459,7 +407,7 @@ public final class EmulationActivity extends AppCompatActivity
if (!closeMenu()) if (!closeMenu())
{ {
// Removing the menu failed, so that means it wasn't visible. Add it. // Removing the menu failed, so that means it wasn't visible. Add it.
Fragment fragment = MenuFragment.newInstance(mSelectedTitle); Fragment fragment = MenuFragment.newInstance();
getSupportFragmentManager().beginTransaction() getSupportFragmentManager().beginTransaction()
.setCustomAnimations( .setCustomAnimations(
R.animator.menu_slide_in_from_start, R.animator.menu_slide_in_from_start,
@ -478,7 +426,8 @@ public final class EmulationActivity extends AppCompatActivity
PopupMenu popup = new PopupMenu(this, anchor); PopupMenu popup = new PopupMenu(this, anchor);
Menu menu = popup.getMenu(); Menu menu = popup.getMenu();
int id = sIsGameCubeGame ? R.menu.menu_overlay_controls_gc : R.menu.menu_overlay_controls_wii; boolean wii = NativeLibrary.IsEmulatingWii();
int id = wii ? R.menu.menu_overlay_controls_wii : R.menu.menu_overlay_controls_gc;
popup.getMenuInflater().inflate(id, menu); popup.getMenuInflater().inflate(id, menu);
// Populate the checkbox value for joystick center on touch // Populate the checkbox value for joystick center on touch
@ -748,7 +697,7 @@ public final class EmulationActivity extends AppCompatActivity
{ {
AlertDialog.Builder builder = new AlertDialog.Builder(this, R.style.DolphinDialogBase); AlertDialog.Builder builder = new AlertDialog.Builder(this, R.style.DolphinDialogBase);
builder.setTitle(R.string.emulation_toggle_controls); builder.setTitle(R.string.emulation_toggle_controls);
if (sIsGameCubeGame || mPreferences.getInt("wiiController", 3) == 0) if (!NativeLibrary.IsEmulatingWii() || mPreferences.getInt("wiiController", 3) == 0)
{ {
boolean[] gcEnabledButtons = new boolean[11]; boolean[] gcEnabledButtons = new boolean[11];
String gcSettingBase = "MAIN_BUTTON_TOGGLE_GC_"; String gcSettingBase = "MAIN_BUTTON_TOGGLE_GC_";
@ -972,7 +921,7 @@ public final class EmulationActivity extends AppCompatActivity
private void setIRSensitivity() private void setIRSensitivity()
{ {
// IR settings always get saved per-game since WiimoteNew.ini is wiped upon reinstall. // IR settings always get saved per-game since WiimoteNew.ini is wiped upon reinstall.
File file = SettingsFile.getCustomGameSettingsFile(mSelectedGameId); File file = SettingsFile.getCustomGameSettingsFile(NativeLibrary.GetCurrentGameID());
IniFile ini = new IniFile(file); IniFile ini = new IniFile(file);
int ir_pitch = ini.getInt(Settings.SECTION_CONTROLS, SettingsFile.KEY_WIIBIND_IR_PITCH, 15); int ir_pitch = ini.getInt(Settings.SECTION_CONTROLS, SettingsFile.KEY_WIIBIND_IR_PITCH, 15);
@ -1214,16 +1163,6 @@ public final class EmulationActivity extends AppCompatActivity
.commit(); .commit();
} }
public String getSelectedTitle()
{
return mSelectedTitle;
}
public static boolean isGameCubeGame()
{
return sIsGameCubeGame;
}
public boolean isActivityRecreated() public boolean isActivityRecreated()
{ {
return activityRecreated; return activityRecreated;

View File

@ -138,7 +138,8 @@ public final class GameAdapter extends RecyclerView.Adapter<GameViewHolder> impl
{ {
GameViewHolder holder = (GameViewHolder) view.getTag(); GameViewHolder holder = (GameViewHolder) view.getTag();
EmulationActivity.launch((FragmentActivity) view.getContext(), holder.gameFile); String[] paths = GameFileCacheService.findSecondDiscAndGetPaths(holder.gameFile);
EmulationActivity.launch((FragmentActivity) view.getContext(), paths);
} }
/** /**

View File

@ -26,6 +26,7 @@ public final class MenuFragment extends Fragment implements View.OnClickListener
private View mUnpauseEmulation; private View mUnpauseEmulation;
private static final String KEY_TITLE = "title"; private static final String KEY_TITLE = "title";
private static final String KEY_WII = "wii";
private static SparseIntArray buttonsActionsMap = new SparseIntArray(); private static SparseIntArray buttonsActionsMap = new SparseIntArray();
static static
@ -55,12 +56,16 @@ public final class MenuFragment extends Fragment implements View.OnClickListener
EmulationActivity.MENU_ACTION_SETTINGS_GRAPHICS); EmulationActivity.MENU_ACTION_SETTINGS_GRAPHICS);
} }
public static MenuFragment newInstance(String title) public static MenuFragment newInstance()
{ {
MenuFragment fragment = new MenuFragment(); MenuFragment fragment = new MenuFragment();
Bundle arguments = new Bundle(); Bundle arguments = new Bundle();
arguments.putSerializable(KEY_TITLE, title); if (NativeLibrary.IsGameMetadataValid())
{
arguments.putString(KEY_TITLE, NativeLibrary.GetCurrentTitleDescription());
arguments.putBoolean(KEY_WII, NativeLibrary.IsEmulatingWii());
}
fragment.setArguments(arguments); fragment.setArguments(arguments);
return fragment; return fragment;
@ -93,7 +98,7 @@ public final class MenuFragment extends Fragment implements View.OnClickListener
options.findViewById(R.id.menu_overlay_controls).setVisibility(View.GONE); options.findViewById(R.id.menu_overlay_controls).setVisibility(View.GONE);
} }
if (EmulationActivity.isGameCubeGame()) if (!getArguments().getBoolean(KEY_WII, true))
{ {
options.findViewById(R.id.menu_refresh_wiimotes).setVisibility(View.GONE); options.findViewById(R.id.menu_refresh_wiimotes).setVisibility(View.GONE);
} }
@ -131,7 +136,7 @@ public final class MenuFragment extends Fragment implements View.OnClickListener
rootView.findViewById(R.id.menu_exit).setOnClickListener(this); rootView.findViewById(R.id.menu_exit).setOnClickListener(this);
mTitleText = rootView.findViewById(R.id.text_game_title); mTitleText = rootView.findViewById(R.id.text_game_title);
String title = getArguments().getString(KEY_TITLE); String title = getArguments().getString(KEY_TITLE, null);
if (title != null) if (title != null)
{ {
mTitleText.setText(title); mTitleText.setText(title);

View File

@ -124,17 +124,20 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener
if (!mPreferences.getBoolean("OverlayInitV3", false)) if (!mPreferences.getBoolean("OverlayInitV3", false))
defaultOverlay(); defaultOverlay();
// Load the controls. // Load the controls if we can. If not, EmulationActivity has to do it later.
if (NativeLibrary.IsRunning()) if (NativeLibrary.IsGameMetadataValid())
{ {
// We would've needed a refreshControls call here in addition to the initTouchPointer call if (NativeLibrary.IsRunning())
// if it wasn't for initTouchPointer calling refreshControls. {
initTouchPointer(); // We would've needed a refreshControls call here in addition to the initTouchPointer call
} // if it wasn't for initTouchPointer calling refreshControls.
else initTouchPointer();
{ }
// We can't call initTouchPointer yet because it needs the aspect ratio of the running game. else
refreshControls(); {
// We can't call initTouchPointer yet because it needs the aspect ratio of the running game.
refreshControls();
}
} }
// Set the on touch listener. // Set the on touch listener.
@ -152,7 +155,7 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener
// Refresh before starting the pointer // Refresh before starting the pointer
refreshControls(); refreshControls();
if (!EmulationActivity.isGameCubeGame()) if (!NativeLibrary.IsEmulatingWii())
{ {
int doubleTapButton = IntSetting.MAIN_DOUBLE_TAP_BUTTON.getIntGlobal(); int doubleTapButton = IntSetting.MAIN_DOUBLE_TAP_BUTTON.getIntGlobal();
@ -715,7 +718,7 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener
if (BooleanSetting.MAIN_SHOW_INPUT_OVERLAY.getBooleanGlobal()) if (BooleanSetting.MAIN_SHOW_INPUT_OVERLAY.getBooleanGlobal())
{ {
// Add all the enabled overlay items back to the HashSet. // 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)); IniFile dolphinIni = new IniFile(SettingsFile.getSettingsFile(Settings.FILE_DOLPHIN));
@ -775,7 +778,7 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener
getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE; getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE;
// Values for these come from R.array.controllersEntries // 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) if (isLandscape)
gcDefaultOverlay(); gcDefaultOverlay();

View File

@ -86,6 +86,15 @@ public final class GameFileCacheService extends IntentService
return matchWithoutRevision; 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() public static boolean hasLoadedCache()
{ {
return hasLoadedCache.get(); return hasLoadedCache.get();

View File

@ -201,7 +201,7 @@ public final class MainActivity extends AppCompatActivity implements MainView
break; break;
case MainPresenter.REQUEST_GAME_FILE: case MainPresenter.REQUEST_GAME_FILE:
EmulationActivity.launchFile(this, FileBrowserHelper.getSelectedFiles(result)); EmulationActivity.launch(this, FileBrowserHelper.getSelectedFiles(result));
break; break;
case MainPresenter.REQUEST_WAD_FILE: case MainPresenter.REQUEST_WAD_FILE:

View File

@ -142,7 +142,8 @@ public final class TvMainActivity extends FragmentActivity implements MainView
TvGameViewHolder holder = (TvGameViewHolder) itemViewHolder; TvGameViewHolder holder = (TvGameViewHolder) itemViewHolder;
// Start the emulation activity and send the path of the clicked ISO to it. // 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 @@ public final class TvMainActivity extends FragmentActivity implements MainView
break; break;
case MainPresenter.REQUEST_GAME_FILE: case MainPresenter.REQUEST_GAME_FILE:
EmulationActivity.launchFile(this, FileBrowserHelper.getSelectedFiles(result)); EmulationActivity.launch(this, FileBrowserHelper.getSelectedFiles(result));
break; break;
case MainPresenter.REQUEST_WAD_FILE: case MainPresenter.REQUEST_WAD_FILE:

View File

@ -48,7 +48,7 @@ public final class StartupHandler
if (start_files != null && start_files.length > 0) if (start_files != null && start_files.length > 0)
{ {
// Start the emulation activity, send the ISO passed in and finish the main activity // 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(); parent.finish();
} }
} }

View File

@ -13,7 +13,8 @@ static JavaVM* s_java_vm;
static jclass s_native_library_class; static jclass s_native_library_class;
static jmethodID s_display_alert_msg; static jmethodID s_display_alert_msg;
static jmethodID s_do_rumble; 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 jclass s_game_file_class;
static jfieldID s_game_file_pointer; static jfieldID s_game_file_pointer;
@ -85,7 +86,12 @@ jmethodID GetDoRumble()
jmethodID GetUpdateTouchPointer() jmethodID GetUpdateTouchPointer()
{ {
return s_get_update_touch_pointer; return s_update_touch_pointer;
}
jmethodID GetOnTitleChanged()
{
return s_on_title_changed;
} }
jclass GetAnalyticsClass() jclass GetAnalyticsClass()
@ -212,8 +218,9 @@ jint JNI_OnLoad(JavaVM* vm, void* reserved)
s_display_alert_msg = env->GetStaticMethodID(s_native_library_class, "displayAlertMsg", s_display_alert_msg = env->GetStaticMethodID(s_native_library_class, "displayAlertMsg",
"(Ljava/lang/String;Ljava/lang/String;ZZ)Z"); "(Ljava/lang/String;Ljava/lang/String;ZZ)Z");
s_do_rumble = env->GetStaticMethodID(s_native_library_class, "rumble", "(ID)V"); 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"); 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); env->DeleteLocalRef(native_library_class);
const jclass game_file_class = env->FindClass("org/dolphinemu/dolphinemu/model/GameFile"); const jclass game_file_class = env->FindClass("org/dolphinemu/dolphinemu/model/GameFile");

View File

@ -16,6 +16,7 @@ jclass GetNativeLibraryClass();
jmethodID GetDisplayAlertMsg(); jmethodID GetDisplayAlertMsg();
jmethodID GetDoRumble(); jmethodID GetDoRumble();
jmethodID GetUpdateTouchPointer(); jmethodID GetUpdateTouchPointer();
jmethodID GetOnTitleChanged();
jclass GetAnalyticsClass(); jclass GetAnalyticsClass();
jmethodID GetSendAnalyticsReport(); jmethodID GetSendAnalyticsReport();

View File

@ -80,6 +80,7 @@ std::mutex s_host_identity_lock;
Common::Event s_update_main_frame_event; Common::Event s_update_main_frame_event;
Common::Event s_emulation_end_event; Common::Event s_emulation_end_event;
bool s_have_wm_user_stop = false; bool s_have_wm_user_stop = false;
bool s_game_metadata_is_valid = false;
} // Anonymous namespace } // Anonymous namespace
void UpdatePointer() void UpdatePointer()
@ -149,6 +150,10 @@ void Host_YieldToUI()
void Host_TitleChanged() 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) 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(); Core::Shutdown();
ButtonManager::Shutdown(); ButtonManager::Shutdown();
guard.unlock(); guard.unlock();
@ -752,6 +758,36 @@ JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SetObscuredP
OSD::SetObscuredPixelsTop(height); 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 #ifdef __cplusplus
} }
#endif #endif

View File

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

View File

@ -681,12 +681,14 @@ void SConfig::SetRunningGameMetadata(const std::string& game_id, const std::stri
if (game_id == "00000000") if (game_id == "00000000")
{ {
m_title_name.clear();
m_title_description.clear(); m_title_description.clear();
return; return;
} }
const Core::TitleDatabase title_database; const Core::TitleDatabase title_database;
const DiscIO::Language language = GetLanguageAdjustedForRegion(bWii, region); 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); m_title_description = title_database.Describe(m_gametdb_id, language);
NOTICE_LOG(CORE, "Active title: %s", m_title_description.c_str()); NOTICE_LOG(CORE, "Active title: %s", m_title_description.c_str());
Host_TitleChanged(); Host_TitleChanged();
@ -819,10 +821,10 @@ struct SetGameMetadata
SetGameMetadata(SConfig* config_, DiscIO::Region* region_) : config(config_), region(region_) {} SetGameMetadata(SConfig* config_, DiscIO::Region* region_) : config(config_), region(region_) {}
bool operator()(const BootParameters::Disc& disc) const 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->bWii = disc.volume->GetVolumeType() == DiscIO::Platform::WiiDisc;
config->m_disc_booted_from_game_list = true; config->m_disc_booted_from_game_list = true;
*region = disc.volume->GetRegion(); config->SetRunningGameMetadata(*disc.volume, disc.volume->GetGamePartition());
return true; return true;
} }
@ -831,12 +833,14 @@ struct SetGameMetadata
if (!executable.reader->IsValid()) if (!executable.reader->IsValid())
return false; return false;
config->bWii = executable.reader->IsWii();
*region = DiscIO::Region::Unknown; *region = DiscIO::Region::Unknown;
config->bWii = executable.reader->IsWii();
// Strip the .elf/.dol file extension and directories before the name // Strip the .elf/.dol file extension and directories before the name
SplitPath(executable.path, nullptr, &config->m_debugger_game_id, nullptr); SplitPath(executable.path, nullptr, &config->m_debugger_game_id, nullptr);
Host_TitleChanged();
return true; return true;
} }
@ -854,9 +858,10 @@ struct SetGameMetadata
} }
const IOS::ES::TMDReader& tmd = wad.GetTMD(); const IOS::ES::TMDReader& tmd = wad.GetTMD();
config->SetRunningGameMetadata(tmd, DiscIO::Platform::WiiWAD);
config->bWii = true;
*region = tmd.GetRegion(); *region = tmd.GetRegion();
config->bWii = true;
config->SetRunningGameMetadata(tmd, DiscIO::Platform::WiiWAD);
return true; return true;
} }
@ -869,16 +874,20 @@ struct SetGameMetadata
PanicAlertT("This title cannot be booted."); PanicAlertT("This title cannot be booted.");
return false; return false;
} }
config->SetRunningGameMetadata(tmd, DiscIO::Platform::WiiWAD);
config->bWii = true;
*region = tmd.GetRegion(); *region = tmd.GetRegion();
config->bWii = true;
config->SetRunningGameMetadata(tmd, DiscIO::Platform::WiiWAD);
return true; return true;
} }
bool operator()(const BootParameters::IPL& ipl) const bool operator()(const BootParameters::IPL& ipl) const
{ {
config->bWii = false;
*region = ipl.region; *region = ipl.region;
config->bWii = false;
Host_TitleChanged();
return true; return true;
} }
@ -888,8 +897,10 @@ struct SetGameMetadata
if (!dff_file) if (!dff_file)
return false; return false;
config->bWii = dff_file->GetIsWii();
*region = DiscIO::Region::NTSC_U; *region = DiscIO::Region::NTSC_U;
config->bWii = dff_file->GetIsWii();
Host_TitleChanged();
return true; return true;
} }

View File

@ -188,6 +188,7 @@ struct SConfig
bool m_disc_booted_from_game_list = false; bool m_disc_booted_from_game_list = false;
const std::string& GetGameID() const { return m_game_id; } 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; } const std::string& GetTitleDescription() const { return m_title_description; }
u64 GetTitleID() const { return m_title_id; } u64 GetTitleID() const { return m_title_id; }
u16 GetRevision() const { return m_revision; } u16 GetRevision() const { return m_revision; }
@ -360,6 +361,7 @@ private:
std::string m_game_id; std::string m_game_id;
std::string m_gametdb_id; std::string m_gametdb_id;
std::string m_title_name;
std::string m_title_description; std::string m_title_description;
u64 m_title_id; u64 m_title_id;
u16 m_revision; u16 m_revision;

View File

@ -85,6 +85,10 @@
#include "VideoCommon/VideoBackendBase.h" #include "VideoCommon/VideoBackendBase.h"
#include "VideoCommon/VideoConfig.h" #include "VideoCommon/VideoConfig.h"
#ifdef ANDROID
#include "jni/AndroidCommon/IDCache.h"
#endif
namespace Core namespace Core
{ {
static bool s_wants_determinism; 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. // This needs to be delayed until after the video backend is ready.
DolphinAnalytics::Instance().ReportGameStart(); 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) if (_CoreParameter.bFastmem)
EMM::InstallExceptionHandler(); // Let's run under memory watch EMM::InstallExceptionHandler(); // Let's run under memory watch