mirror of
https://github.com/libretro/RetroArch.git
synced 2024-11-27 02:00:41 +00:00
(Android/Play Store) Add frontend support for core installation via Play Feature Delivery
This commit is contained in:
parent
2c07234a5d
commit
4799d2d955
@ -2212,6 +2212,15 @@ ifeq ($(HAVE_VITAGL), 1)
|
|||||||
OBJ += $(patsubst %.c,%.o,$(foreach dir,$(SOURCES), $(wildcard $(dir)/*.c)))
|
OBJ += $(patsubst %.c,%.o,$(foreach dir,$(SOURCES), $(wildcard $(dir)/*.c)))
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
#####################################
|
||||||
|
### Android Play Feature Delivery ###
|
||||||
|
### (Play Store build core ###
|
||||||
|
### downloader) ###
|
||||||
|
###############WIP###################
|
||||||
|
ifeq ($(ANDROID), 1)
|
||||||
|
OBJ += play_feature_delivery/play_feature_delivery.o
|
||||||
|
endif
|
||||||
|
|
||||||
##################################
|
##################################
|
||||||
### Classic Platform specifics ###
|
### Classic Platform specifics ###
|
||||||
###############WIP################
|
###############WIP################
|
||||||
|
18
core_info.c
18
core_info.c
@ -36,6 +36,10 @@
|
|||||||
#include "uwp/uwp_func.h"
|
#include "uwp/uwp_func.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(ANDROID)
|
||||||
|
#include "play_feature_delivery/play_feature_delivery.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
enum compare_op
|
enum compare_op
|
||||||
{
|
{
|
||||||
COMPARE_OP_EQUAL = 0,
|
COMPARE_OP_EQUAL = 0,
|
||||||
@ -1524,6 +1528,13 @@ bool core_info_set_core_lock(const char *core_path, bool lock)
|
|||||||
|
|
||||||
lock_file_path[0] = '\0';
|
lock_file_path[0] = '\0';
|
||||||
|
|
||||||
|
#if defined(ANDROID)
|
||||||
|
/* Play Store builds do not support
|
||||||
|
* core locking */
|
||||||
|
if (play_feature_delivery_enabled())
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
|
||||||
if (string_is_empty(core_path))
|
if (string_is_empty(core_path))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@ -1599,6 +1610,13 @@ bool core_info_get_core_lock(const char *core_path, bool validate_path)
|
|||||||
|
|
||||||
lock_file_path[0] = '\0';
|
lock_file_path[0] = '\0';
|
||||||
|
|
||||||
|
#if defined(ANDROID)
|
||||||
|
/* Play Store builds do not support
|
||||||
|
* core locking */
|
||||||
|
if (play_feature_delivery_enabled())
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
|
||||||
if (string_is_empty(core_path))
|
if (string_is_empty(core_path))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -36,6 +36,7 @@
|
|||||||
struct core_updater_list
|
struct core_updater_list
|
||||||
{
|
{
|
||||||
core_updater_list_entry_t *entries;
|
core_updater_list_entry_t *entries;
|
||||||
|
enum core_updater_list_type type;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Cached ('global') core updater list */
|
/* Cached ('global') core updater list */
|
||||||
@ -109,6 +110,7 @@ core_updater_list_t *core_updater_list_init(void)
|
|||||||
|
|
||||||
/* Initialise members */
|
/* Initialise members */
|
||||||
core_list->entries = NULL;
|
core_list->entries = NULL;
|
||||||
|
core_list->type = CORE_UPDATER_LIST_TYPE_UNKNOWN;
|
||||||
|
|
||||||
return core_list;
|
return core_list;
|
||||||
}
|
}
|
||||||
@ -129,6 +131,8 @@ void core_updater_list_reset(core_updater_list_t *core_list)
|
|||||||
|
|
||||||
RBUF_FREE(core_list->entries);
|
RBUF_FREE(core_list->entries);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
core_list->type = CORE_UPDATER_LIST_TYPE_UNKNOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Frees specified core updater list */
|
/* Frees specified core updater list */
|
||||||
@ -194,6 +198,17 @@ size_t core_updater_list_size(core_updater_list_t *core_list)
|
|||||||
return RBUF_LEN(core_list->entries);
|
return RBUF_LEN(core_list->entries);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Returns 'type' (core delivery method) of
|
||||||
|
* specified core updater list */
|
||||||
|
enum core_updater_list_type core_updater_list_get_type(
|
||||||
|
core_updater_list_t *core_list)
|
||||||
|
{
|
||||||
|
if (!core_list)
|
||||||
|
return CORE_UPDATER_LIST_TYPE_UNKNOWN;
|
||||||
|
|
||||||
|
return core_list->type;
|
||||||
|
}
|
||||||
|
|
||||||
/* Fetches core updater list entry corresponding
|
/* Fetches core updater list entry corresponding
|
||||||
* to the specified entry index.
|
* to the specified entry index.
|
||||||
* Returns false if index is invalid. */
|
* Returns false if index is invalid. */
|
||||||
@ -371,7 +386,8 @@ static bool core_updater_list_set_paths(
|
|||||||
const char *path_dir_libretro,
|
const char *path_dir_libretro,
|
||||||
const char *path_libretro_info,
|
const char *path_libretro_info,
|
||||||
const char *network_buildbot_url,
|
const char *network_buildbot_url,
|
||||||
const char *filename_str)
|
const char *filename_str,
|
||||||
|
enum core_updater_list_type list_type)
|
||||||
{
|
{
|
||||||
char *last_underscore = NULL;
|
char *last_underscore = NULL;
|
||||||
char *tmp_url = NULL;
|
char *tmp_url = NULL;
|
||||||
@ -384,11 +400,14 @@ static bool core_updater_list_set_paths(
|
|||||||
local_core_path[0] = '\0';
|
local_core_path[0] = '\0';
|
||||||
local_info_path[0] = '\0';
|
local_info_path[0] = '\0';
|
||||||
|
|
||||||
if (!entry || string_is_empty(filename_str))
|
if (!entry ||
|
||||||
|
string_is_empty(filename_str) ||
|
||||||
|
string_is_empty(path_dir_libretro) ||
|
||||||
|
string_is_empty(path_libretro_info))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (string_is_empty(path_dir_libretro) ||
|
/* Only buildbot cores require the buildbot URL */
|
||||||
string_is_empty(path_libretro_info) ||
|
if ((list_type == CORE_UPDATER_LIST_TYPE_BUILDBOT) &&
|
||||||
string_is_empty(network_buildbot_url))
|
string_is_empty(network_buildbot_url))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@ -404,7 +423,10 @@ static bool core_updater_list_set_paths(
|
|||||||
|
|
||||||
entry->remote_filename = strdup(filename_str);
|
entry->remote_filename = strdup(filename_str);
|
||||||
|
|
||||||
/* remote_core_path */
|
/* remote_core_path
|
||||||
|
* > Leave blank if this is not a buildbot core */
|
||||||
|
if (list_type == CORE_UPDATER_LIST_TYPE_BUILDBOT)
|
||||||
|
{
|
||||||
fill_pathname_join(
|
fill_pathname_join(
|
||||||
remote_core_path,
|
remote_core_path,
|
||||||
network_buildbot_url,
|
network_buildbot_url,
|
||||||
@ -418,6 +440,7 @@ static bool core_updater_list_set_paths(
|
|||||||
remote_core_path, tmp_url, sizeof(remote_core_path));
|
remote_core_path, tmp_url, sizeof(remote_core_path));
|
||||||
if (tmp_url)
|
if (tmp_url)
|
||||||
free(tmp_url);
|
free(tmp_url);
|
||||||
|
}
|
||||||
|
|
||||||
if (entry->remote_core_path)
|
if (entry->remote_core_path)
|
||||||
{
|
{
|
||||||
@ -677,7 +700,8 @@ static void core_updater_list_add_entry(
|
|||||||
path_dir_libretro,
|
path_dir_libretro,
|
||||||
path_libretro_info,
|
path_libretro_info,
|
||||||
network_buildbot_url,
|
network_buildbot_url,
|
||||||
filename_str))
|
filename_str,
|
||||||
|
CORE_UPDATER_LIST_TYPE_BUILDBOT))
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
if (!core_updater_list_set_core_info(
|
if (!core_updater_list_set_core_info(
|
||||||
@ -825,6 +849,9 @@ bool core_updater_list_parse_network_data(
|
|||||||
/* Sort completed list */
|
/* Sort completed list */
|
||||||
core_updater_list_qsort(core_list);
|
core_updater_list_qsort(core_list);
|
||||||
|
|
||||||
|
/* Set list type */
|
||||||
|
core_list->type = CORE_UPDATER_LIST_TYPE_BUILDBOT;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
@ -835,3 +862,114 @@ error:
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Parses a single play feature delivery core
|
||||||
|
* listing and adds it to the specified core
|
||||||
|
* updater list */
|
||||||
|
static void core_updater_list_add_pfd_entry(
|
||||||
|
core_updater_list_t *core_list,
|
||||||
|
const char *path_dir_libretro,
|
||||||
|
const char *path_libretro_info,
|
||||||
|
const char *filename_str)
|
||||||
|
{
|
||||||
|
const core_updater_list_entry_t *search_entry = NULL;
|
||||||
|
core_updater_list_entry_t entry = {0};
|
||||||
|
|
||||||
|
if (!core_list || string_is_empty(filename_str))
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
/* Check whether core file is already included
|
||||||
|
* in the list (this is *not* an error condition,
|
||||||
|
* it just means we can skip the current listing) */
|
||||||
|
if (core_updater_list_get_filename(core_list,
|
||||||
|
filename_str, &search_entry))
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
/* Note: Play feature delivery cores have no
|
||||||
|
* timestamp or CRC info - leave these fields
|
||||||
|
* zero initialised */
|
||||||
|
|
||||||
|
/* Populate entry fields */
|
||||||
|
if (!core_updater_list_set_paths(
|
||||||
|
&entry,
|
||||||
|
path_dir_libretro,
|
||||||
|
path_libretro_info,
|
||||||
|
NULL,
|
||||||
|
filename_str,
|
||||||
|
CORE_UPDATER_LIST_TYPE_PFD))
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
if (!core_updater_list_set_core_info(
|
||||||
|
&entry,
|
||||||
|
entry.local_info_path,
|
||||||
|
filename_str))
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
/* Add entry to list */
|
||||||
|
if (!core_updater_list_push_entry(core_list, &entry))
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
error:
|
||||||
|
/* This is not a *fatal* error - it just
|
||||||
|
* means one of the following:
|
||||||
|
* - The core listing entry obtained from the
|
||||||
|
* play feature delivery interface is broken
|
||||||
|
* somehow
|
||||||
|
* - We had insufficient memory to allocate a new
|
||||||
|
* entry in the core updater list
|
||||||
|
* In either case, the current entry is discarded
|
||||||
|
* and we move on to the next one */
|
||||||
|
core_updater_list_free_entry(&entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Reads the list of cores currently available
|
||||||
|
* via play feature delivery (PFD) into the
|
||||||
|
* specified core_updater_list_t object.
|
||||||
|
* Returns false in the event of an error. */
|
||||||
|
bool core_updater_list_parse_pfd_data(
|
||||||
|
core_updater_list_t *core_list,
|
||||||
|
const char *path_dir_libretro,
|
||||||
|
const char *path_libretro_info,
|
||||||
|
const struct string_list *pfd_cores)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
/* Sanity check */
|
||||||
|
if (!core_list || !pfd_cores || (pfd_cores->size < 1))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* We're populating a list 'from scratch' - remove
|
||||||
|
* any existing entries */
|
||||||
|
core_updater_list_reset(core_list);
|
||||||
|
|
||||||
|
/* Loop over play feature delivery core list */
|
||||||
|
for (i = 0; i < pfd_cores->size; i++)
|
||||||
|
{
|
||||||
|
const char *filename_str = pfd_cores->elems[i].data;
|
||||||
|
|
||||||
|
if (string_is_empty(filename_str))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* Parse core file name and add to core
|
||||||
|
* updater list */
|
||||||
|
core_updater_list_add_pfd_entry(
|
||||||
|
core_list,
|
||||||
|
path_dir_libretro,
|
||||||
|
path_libretro_info,
|
||||||
|
filename_str);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Sanity check */
|
||||||
|
if (RBUF_LEN(core_list->entries) < 1)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* Sort completed list */
|
||||||
|
core_updater_list_qsort(core_list);
|
||||||
|
|
||||||
|
/* Set list type */
|
||||||
|
core_list->type = CORE_UPDATER_LIST_TYPE_PFD;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
@ -32,6 +32,18 @@
|
|||||||
|
|
||||||
RETRO_BEGIN_DECLS
|
RETRO_BEGIN_DECLS
|
||||||
|
|
||||||
|
/* Defines all possible 'types' of core
|
||||||
|
* updater list - corresponds to core
|
||||||
|
* delivery method:
|
||||||
|
* > Buildbot
|
||||||
|
* > Play feature delivery (PFD) */
|
||||||
|
enum core_updater_list_type
|
||||||
|
{
|
||||||
|
CORE_UPDATER_LIST_TYPE_UNKNOWN = 0,
|
||||||
|
CORE_UPDATER_LIST_TYPE_BUILDBOT,
|
||||||
|
CORE_UPDATER_LIST_TYPE_PFD
|
||||||
|
};
|
||||||
|
|
||||||
/* Holds all date info for a core file
|
/* Holds all date info for a core file
|
||||||
* on the buildbot */
|
* on the buildbot */
|
||||||
typedef struct
|
typedef struct
|
||||||
@ -99,6 +111,11 @@ void core_updater_list_free_cached(void);
|
|||||||
/* Returns number of entries in core updater list */
|
/* Returns number of entries in core updater list */
|
||||||
size_t core_updater_list_size(core_updater_list_t *core_list);
|
size_t core_updater_list_size(core_updater_list_t *core_list);
|
||||||
|
|
||||||
|
/* Returns 'type' (core delivery method) of
|
||||||
|
* specified core updater list */
|
||||||
|
enum core_updater_list_type core_updater_list_get_type(
|
||||||
|
core_updater_list_t *core_list);
|
||||||
|
|
||||||
/* Fetches core updater list entry corresponding
|
/* Fetches core updater list entry corresponding
|
||||||
* to the specified entry index.
|
* to the specified entry index.
|
||||||
* Returns false if index is invalid. */
|
* Returns false if index is invalid. */
|
||||||
@ -138,6 +155,16 @@ bool core_updater_list_parse_network_data(
|
|||||||
const char *network_buildbot_url,
|
const char *network_buildbot_url,
|
||||||
const char *data, size_t len);
|
const char *data, size_t len);
|
||||||
|
|
||||||
|
/* Reads the list of cores currently available
|
||||||
|
* via play feature delivery (PFD) into the
|
||||||
|
* specified core_updater_list_t object.
|
||||||
|
* Returns false in the event of an error. */
|
||||||
|
bool core_updater_list_parse_pfd_data(
|
||||||
|
core_updater_list_t *core_list,
|
||||||
|
const char *path_dir_libretro,
|
||||||
|
const char *path_libretro_info,
|
||||||
|
const struct string_list *pfd_cores);
|
||||||
|
|
||||||
RETRO_END_DECLS
|
RETRO_END_DECLS
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -1938,6 +1938,16 @@ static void frontend_unix_init(void *data)
|
|||||||
"doVibrate", "(IIII)V");
|
"doVibrate", "(IIII)V");
|
||||||
GET_METHOD_ID(env, android_app->getUserLanguageString, class,
|
GET_METHOD_ID(env, android_app->getUserLanguageString, class,
|
||||||
"getUserLanguageString", "()Ljava/lang/String;");
|
"getUserLanguageString", "()Ljava/lang/String;");
|
||||||
|
GET_METHOD_ID(env, android_app->isPlayStoreBuild, class,
|
||||||
|
"isPlayStoreBuild", "()Z");
|
||||||
|
GET_METHOD_ID(env, android_app->getAvailableCores, class,
|
||||||
|
"getAvailableCores", "()[Ljava/lang/String;");
|
||||||
|
GET_METHOD_ID(env, android_app->getInstalledCores, class,
|
||||||
|
"getInstalledCores", "()[Ljava/lang/String;");
|
||||||
|
GET_METHOD_ID(env, android_app->downloadCore, class,
|
||||||
|
"downloadCore", "(Ljava/lang/String;)V");
|
||||||
|
GET_METHOD_ID(env, android_app->deleteCore, class,
|
||||||
|
"deleteCore", "(Ljava/lang/String;)V");
|
||||||
CALL_OBJ_METHOD(env, obj, android_app->activity->clazz,
|
CALL_OBJ_METHOD(env, obj, android_app->activity->clazz,
|
||||||
android_app->getIntent);
|
android_app->getIntent);
|
||||||
|
|
||||||
|
@ -166,6 +166,12 @@ struct android_app
|
|||||||
jmethodID getUserLanguageString;
|
jmethodID getUserLanguageString;
|
||||||
jmethodID doVibrate;
|
jmethodID doVibrate;
|
||||||
|
|
||||||
|
jmethodID isPlayStoreBuild;
|
||||||
|
jmethodID getAvailableCores;
|
||||||
|
jmethodID getInstalledCores;
|
||||||
|
jmethodID downloadCore;
|
||||||
|
jmethodID deleteCore;
|
||||||
|
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
unsigned width, height;
|
unsigned width, height;
|
||||||
|
@ -1671,3 +1671,10 @@ MISC FILE FORMATS
|
|||||||
TIME
|
TIME
|
||||||
============================================================ */
|
============================================================ */
|
||||||
#include "../libretro-common/time/rtime.c"
|
#include "../libretro-common/time/rtime.c"
|
||||||
|
|
||||||
|
/*============================================================
|
||||||
|
ANDROID PLAY FEATURE DELIVERY
|
||||||
|
============================================================ */
|
||||||
|
#if defined(ANDROID)
|
||||||
|
#include "../play_feature_delivery/play_feature_delivery.c"
|
||||||
|
#endif
|
||||||
|
@ -10084,6 +10084,10 @@ MSG_HASH(
|
|||||||
MSG_CORE_INSTALLED,
|
MSG_CORE_INSTALLED,
|
||||||
"Core installed: "
|
"Core installed: "
|
||||||
)
|
)
|
||||||
|
MSG_HASH(
|
||||||
|
MSG_CORE_INSTALL_FAILED,
|
||||||
|
"Failed to install core: "
|
||||||
|
)
|
||||||
MSG_HASH(
|
MSG_HASH(
|
||||||
MSG_SCANNING_CORES,
|
MSG_SCANNING_CORES,
|
||||||
"Scanning cores..."
|
"Scanning cores..."
|
||||||
|
@ -89,6 +89,10 @@
|
|||||||
#include "../../uwp/uwp_func.h"
|
#include "../../uwp/uwp_func.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(ANDROID)
|
||||||
|
#include "../../play_feature_delivery/play_feature_delivery.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
ACTION_OK_LOAD_PRESET = 0,
|
ACTION_OK_LOAD_PRESET = 0,
|
||||||
@ -4021,7 +4025,9 @@ static int action_ok_core_updater_list(const char *path,
|
|||||||
const char *label, unsigned type, size_t idx, size_t entry_idx)
|
const char *label, unsigned type, size_t idx, size_t entry_idx)
|
||||||
{
|
{
|
||||||
core_updater_list_t *core_list = NULL;
|
core_updater_list_t *core_list = NULL;
|
||||||
bool refresh = true;
|
settings_t *settings = config_get_ptr();
|
||||||
|
const char *path_dir_libretro = settings->paths.directory_libretro;
|
||||||
|
const char *path_libretro_info = settings->paths.path_libretro_info;
|
||||||
|
|
||||||
/* Get cached core updater list, initialising
|
/* Get cached core updater list, initialising
|
||||||
* it if required */
|
* it if required */
|
||||||
@ -4036,12 +4042,49 @@ static int action_ok_core_updater_list(const char *path,
|
|||||||
return menu_cbs_exit();
|
return menu_cbs_exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(ANDROID)
|
||||||
|
if (play_feature_delivery_enabled())
|
||||||
|
{
|
||||||
|
/* Core downloads are handled via play
|
||||||
|
* feature delivery
|
||||||
|
* > Core list can be populated directly
|
||||||
|
* using the play feature delivery
|
||||||
|
* interface */
|
||||||
|
struct string_list *available_cores =
|
||||||
|
play_feature_delivery_available_cores();
|
||||||
|
bool success = false;
|
||||||
|
|
||||||
|
if (!available_cores)
|
||||||
|
return menu_cbs_exit();
|
||||||
|
|
||||||
|
core_updater_list_reset(core_list);
|
||||||
|
|
||||||
|
success = core_updater_list_parse_pfd_data(
|
||||||
|
core_list,
|
||||||
|
path_dir_libretro,
|
||||||
|
path_libretro_info,
|
||||||
|
available_cores);
|
||||||
|
|
||||||
|
string_list_free(available_cores);
|
||||||
|
|
||||||
|
if (!success)
|
||||||
|
return menu_cbs_exit();
|
||||||
|
|
||||||
|
/* Ensure network is initialised */
|
||||||
|
generic_action_ok_command(CMD_EVENT_NETWORK_INIT);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
bool refresh = true;
|
||||||
|
|
||||||
/* Initial setup... */
|
/* Initial setup... */
|
||||||
menu_entries_ctl(MENU_ENTRIES_CTL_SET_REFRESH, &refresh);
|
menu_entries_ctl(MENU_ENTRIES_CTL_SET_REFRESH, &refresh);
|
||||||
generic_action_ok_command(CMD_EVENT_NETWORK_INIT);
|
generic_action_ok_command(CMD_EVENT_NETWORK_INIT);
|
||||||
|
|
||||||
/* Push core list update task */
|
/* Push core list update task */
|
||||||
task_push_get_core_updater_list(core_list, false, true);
|
task_push_get_core_updater_list(core_list, false, true);
|
||||||
|
}
|
||||||
|
|
||||||
return generic_action_ok_displaylist_push(
|
return generic_action_ok_displaylist_push(
|
||||||
path, NULL, label, type, idx, entry_idx,
|
path, NULL, label, type, idx, entry_idx,
|
||||||
@ -4466,6 +4509,14 @@ static int action_ok_core_updater_download(const char *path,
|
|||||||
if (!core_list)
|
if (!core_list)
|
||||||
return menu_cbs_exit();
|
return menu_cbs_exit();
|
||||||
|
|
||||||
|
#if defined(ANDROID)
|
||||||
|
/* Play Store builds install cores via
|
||||||
|
* the play feature delivery interface */
|
||||||
|
if (play_feature_delivery_enabled())
|
||||||
|
task_push_play_feature_delivery_core_install(
|
||||||
|
core_list, path);
|
||||||
|
else
|
||||||
|
#endif
|
||||||
task_push_core_updater_download(
|
task_push_core_updater_download(
|
||||||
core_list, path, 0, false,
|
core_list, path, 0, false,
|
||||||
auto_backup, (size_t)auto_backup_history_size,
|
auto_backup, (size_t)auto_backup_history_size,
|
||||||
@ -6677,6 +6728,23 @@ static int action_ok_core_delete(const char *path,
|
|||||||
generic_action_ok_command(CMD_EVENT_UNLOAD_CORE);
|
generic_action_ok_command(CMD_EVENT_UNLOAD_CORE);
|
||||||
|
|
||||||
/* Delete core file */
|
/* Delete core file */
|
||||||
|
#if defined(ANDROID)
|
||||||
|
/* If this is a Play Store build and the
|
||||||
|
* core is currently installed via
|
||||||
|
* play feature delivery, must delete
|
||||||
|
* the core via the play feature delivery
|
||||||
|
* interface */
|
||||||
|
if (play_feature_delivery_enabled())
|
||||||
|
{
|
||||||
|
const char *core_filename = path_basename(core_path);
|
||||||
|
|
||||||
|
if (play_feature_delivery_core_installed(core_filename))
|
||||||
|
play_feature_delivery_delete(core_filename);
|
||||||
|
else
|
||||||
|
filestream_delete(core_path);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif
|
||||||
filestream_delete(core_path);
|
filestream_delete(core_path);
|
||||||
|
|
||||||
/* Reload core info files */
|
/* Reload core info files */
|
||||||
|
@ -62,6 +62,10 @@
|
|||||||
#include "../frontend/drivers/platform_unix.h"
|
#include "../frontend/drivers/platform_unix.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(ANDROID)
|
||||||
|
#include "../play_feature_delivery/play_feature_delivery.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_CDROM
|
#ifdef HAVE_CDROM
|
||||||
#include <vfs/vfs_implementation_cdrom.h>
|
#include <vfs/vfs_implementation_cdrom.h>
|
||||||
#include <media/media_detect_cd.h>
|
#include <media/media_detect_cd.h>
|
||||||
@ -670,6 +674,12 @@ end:
|
|||||||
/* Check whether core is currently locked */
|
/* Check whether core is currently locked */
|
||||||
bool core_locked = core_info_get_core_lock(core_path, true);
|
bool core_locked = core_info_get_core_lock(core_path, true);
|
||||||
|
|
||||||
|
#if defined(ANDROID)
|
||||||
|
/* Play Store builds do not support
|
||||||
|
* core locking */
|
||||||
|
if (!play_feature_delivery_enabled())
|
||||||
|
#endif
|
||||||
|
{
|
||||||
/* Lock core
|
/* Lock core
|
||||||
* > Note: Have to set core_path as both the
|
* > Note: Have to set core_path as both the
|
||||||
* 'path' and 'label' parameters (otherwise
|
* 'path' and 'label' parameters (otherwise
|
||||||
@ -686,6 +696,7 @@ end:
|
|||||||
info->list, count, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CORE_LOCK));
|
info->list, count, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CORE_LOCK));
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Backup core */
|
/* Backup core */
|
||||||
if (menu_entries_append_enum(info->list,
|
if (menu_entries_append_enum(info->list,
|
||||||
@ -11054,6 +11065,12 @@ bool menu_displaylist_ctl(enum menu_displaylist_ctl_state type,
|
|||||||
MENU_SETTING_ACTION, 0, 0))
|
MENU_SETTING_ACTION, 0, 0))
|
||||||
count++;
|
count++;
|
||||||
|
|
||||||
|
#if defined(ANDROID)
|
||||||
|
/* Play Store builds auto-update installed
|
||||||
|
* cores, rendering the 'update installed
|
||||||
|
* cores' option irrelevant/useless */
|
||||||
|
if (!play_feature_delivery_enabled())
|
||||||
|
#endif
|
||||||
if (menu_entries_append_enum(info->list,
|
if (menu_entries_append_enum(info->list,
|
||||||
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_UPDATE_INSTALLED_CORES),
|
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_UPDATE_INSTALLED_CORES),
|
||||||
msg_hash_to_str(MENU_ENUM_LABEL_UPDATE_INSTALLED_CORES),
|
msg_hash_to_str(MENU_ENUM_LABEL_UPDATE_INSTALLED_CORES),
|
||||||
|
@ -118,6 +118,10 @@
|
|||||||
#include <3ds/services/cfgu.h>
|
#include <3ds/services/cfgu.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(ANDROID)
|
||||||
|
#include "../play_feature_delivery/play_feature_delivery.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#define _3_SECONDS 3000000
|
#define _3_SECONDS 3000000
|
||||||
#define _6_SECONDS 6000000
|
#define _6_SECONDS 6000000
|
||||||
#define _9_SECONDS 9000000
|
#define _9_SECONDS 9000000
|
||||||
@ -16682,6 +16686,13 @@ static bool setting_append_list(
|
|||||||
parent_group = msg_hash_to_str(MENU_ENUM_LABEL_UPDATER_SETTINGS);
|
parent_group = msg_hash_to_str(MENU_ENUM_LABEL_UPDATER_SETTINGS);
|
||||||
START_SUB_GROUP(list, list_info, "State", &group_info, &subgroup_info, parent_group);
|
START_SUB_GROUP(list, list_info, "State", &group_info, &subgroup_info, parent_group);
|
||||||
#ifdef HAVE_NETWORKING
|
#ifdef HAVE_NETWORKING
|
||||||
|
|
||||||
|
#if defined(ANDROID)
|
||||||
|
/* Play Store builds do not fetch cores
|
||||||
|
* from the buildbot */
|
||||||
|
if (!play_feature_delivery_enabled())
|
||||||
|
#endif
|
||||||
|
{
|
||||||
CONFIG_STRING(
|
CONFIG_STRING(
|
||||||
list, list_info,
|
list, list_info,
|
||||||
settings->paths.network_buildbot_url,
|
settings->paths.network_buildbot_url,
|
||||||
@ -16697,6 +16708,7 @@ static bool setting_append_list(
|
|||||||
SETTINGS_DATA_LIST_CURRENT_ADD_FLAGS(list, list_info, SD_FLAG_ALLOW_INPUT);
|
SETTINGS_DATA_LIST_CURRENT_ADD_FLAGS(list, list_info, SD_FLAG_ALLOW_INPUT);
|
||||||
(*list)[list_info->index - 1].ui_type = ST_UI_TYPE_STRING_LINE_EDIT;
|
(*list)[list_info->index - 1].ui_type = ST_UI_TYPE_STRING_LINE_EDIT;
|
||||||
(*list)[list_info->index - 1].action_start = setting_generic_action_start_default;
|
(*list)[list_info->index - 1].action_start = setting_generic_action_start_default;
|
||||||
|
}
|
||||||
|
|
||||||
CONFIG_STRING(
|
CONFIG_STRING(
|
||||||
list, list_info,
|
list, list_info,
|
||||||
@ -16746,6 +16758,12 @@ static bool setting_append_list(
|
|||||||
SD_FLAG_NONE
|
SD_FLAG_NONE
|
||||||
);
|
);
|
||||||
|
|
||||||
|
#if defined(ANDROID)
|
||||||
|
/* Play Store builds do not support automatic
|
||||||
|
* core backups */
|
||||||
|
if (!play_feature_delivery_enabled())
|
||||||
|
#endif
|
||||||
|
{
|
||||||
CONFIG_BOOL(
|
CONFIG_BOOL(
|
||||||
list, list_info,
|
list, list_info,
|
||||||
&settings->bools.core_updater_auto_backup,
|
&settings->bools.core_updater_auto_backup,
|
||||||
@ -16777,6 +16795,7 @@ static bool setting_append_list(
|
|||||||
(*list)[list_info->index - 1].action_ok = &setting_action_ok_uint;
|
(*list)[list_info->index - 1].action_ok = &setting_action_ok_uint;
|
||||||
(*list)[list_info->index - 1].offset_by = 1;
|
(*list)[list_info->index - 1].offset_by = 1;
|
||||||
menu_settings_list_current_add_range(list, list_info, (*list)[list_info->index - 1].offset_by, 500, 1, true, true);
|
menu_settings_list_current_add_range(list, list_info, (*list)[list_info->index - 1].offset_by, 500, 1, true, true);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
END_SUB_GROUP(list, list_info, parent_group);
|
END_SUB_GROUP(list, list_info, parent_group);
|
||||||
END_GROUP(list, list_info, parent_group);
|
END_GROUP(list, list_info, parent_group);
|
||||||
|
@ -2073,6 +2073,7 @@ enum msg_hash_enums
|
|||||||
MSG_DOWNLOADING_CORE,
|
MSG_DOWNLOADING_CORE,
|
||||||
MSG_EXTRACTING_CORE,
|
MSG_EXTRACTING_CORE,
|
||||||
MSG_CORE_INSTALLED,
|
MSG_CORE_INSTALLED,
|
||||||
|
MSG_CORE_INSTALL_FAILED,
|
||||||
MSG_SCANNING_CORES,
|
MSG_SCANNING_CORES,
|
||||||
MSG_CHECKING_CORE,
|
MSG_CHECKING_CORE,
|
||||||
MSG_ALL_CORES_UPDATED,
|
MSG_ALL_CORES_UPDATED,
|
||||||
|
@ -0,0 +1,89 @@
|
|||||||
|
/* DO NOT EDIT THIS FILE - it is machine generated */
|
||||||
|
#include <jni.h>
|
||||||
|
/* Header for class com_retroarch_browser_retroactivity_RetroActivityCommon */
|
||||||
|
|
||||||
|
#ifndef _Included_com_retroarch_browser_retroactivity_RetroActivityCommon
|
||||||
|
#define _Included_com_retroarch_browser_retroactivity_RetroActivityCommon
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
#undef com_retroarch_browser_retroactivity_RetroActivityCommon_BIND_ABOVE_CLIENT
|
||||||
|
#define com_retroarch_browser_retroactivity_RetroActivityCommon_BIND_ABOVE_CLIENT 8L
|
||||||
|
#undef com_retroarch_browser_retroactivity_RetroActivityCommon_BIND_ADJUST_WITH_ACTIVITY
|
||||||
|
#define com_retroarch_browser_retroactivity_RetroActivityCommon_BIND_ADJUST_WITH_ACTIVITY 128L
|
||||||
|
#undef com_retroarch_browser_retroactivity_RetroActivityCommon_BIND_ALLOW_OOM_MANAGEMENT
|
||||||
|
#define com_retroarch_browser_retroactivity_RetroActivityCommon_BIND_ALLOW_OOM_MANAGEMENT 16L
|
||||||
|
#undef com_retroarch_browser_retroactivity_RetroActivityCommon_BIND_AUTO_CREATE
|
||||||
|
#define com_retroarch_browser_retroactivity_RetroActivityCommon_BIND_AUTO_CREATE 1L
|
||||||
|
#undef com_retroarch_browser_retroactivity_RetroActivityCommon_BIND_DEBUG_UNBIND
|
||||||
|
#define com_retroarch_browser_retroactivity_RetroActivityCommon_BIND_DEBUG_UNBIND 2L
|
||||||
|
#undef com_retroarch_browser_retroactivity_RetroActivityCommon_BIND_EXTERNAL_SERVICE
|
||||||
|
#define com_retroarch_browser_retroactivity_RetroActivityCommon_BIND_EXTERNAL_SERVICE -2147483648L
|
||||||
|
#undef com_retroarch_browser_retroactivity_RetroActivityCommon_BIND_IMPORTANT
|
||||||
|
#define com_retroarch_browser_retroactivity_RetroActivityCommon_BIND_IMPORTANT 64L
|
||||||
|
#undef com_retroarch_browser_retroactivity_RetroActivityCommon_BIND_INCLUDE_CAPABILITIES
|
||||||
|
#define com_retroarch_browser_retroactivity_RetroActivityCommon_BIND_INCLUDE_CAPABILITIES 4096L
|
||||||
|
#undef com_retroarch_browser_retroactivity_RetroActivityCommon_BIND_NOT_FOREGROUND
|
||||||
|
#define com_retroarch_browser_retroactivity_RetroActivityCommon_BIND_NOT_FOREGROUND 4L
|
||||||
|
#undef com_retroarch_browser_retroactivity_RetroActivityCommon_BIND_NOT_PERCEPTIBLE
|
||||||
|
#define com_retroarch_browser_retroactivity_RetroActivityCommon_BIND_NOT_PERCEPTIBLE 256L
|
||||||
|
#undef com_retroarch_browser_retroactivity_RetroActivityCommon_BIND_WAIVE_PRIORITY
|
||||||
|
#define com_retroarch_browser_retroactivity_RetroActivityCommon_BIND_WAIVE_PRIORITY 32L
|
||||||
|
#undef com_retroarch_browser_retroactivity_RetroActivityCommon_CONTEXT_IGNORE_SECURITY
|
||||||
|
#define com_retroarch_browser_retroactivity_RetroActivityCommon_CONTEXT_IGNORE_SECURITY 2L
|
||||||
|
#undef com_retroarch_browser_retroactivity_RetroActivityCommon_CONTEXT_INCLUDE_CODE
|
||||||
|
#define com_retroarch_browser_retroactivity_RetroActivityCommon_CONTEXT_INCLUDE_CODE 1L
|
||||||
|
#undef com_retroarch_browser_retroactivity_RetroActivityCommon_CONTEXT_RESTRICTED
|
||||||
|
#define com_retroarch_browser_retroactivity_RetroActivityCommon_CONTEXT_RESTRICTED 4L
|
||||||
|
#undef com_retroarch_browser_retroactivity_RetroActivityCommon_MODE_APPEND
|
||||||
|
#define com_retroarch_browser_retroactivity_RetroActivityCommon_MODE_APPEND 32768L
|
||||||
|
#undef com_retroarch_browser_retroactivity_RetroActivityCommon_MODE_ENABLE_WRITE_AHEAD_LOGGING
|
||||||
|
#define com_retroarch_browser_retroactivity_RetroActivityCommon_MODE_ENABLE_WRITE_AHEAD_LOGGING 8L
|
||||||
|
#undef com_retroarch_browser_retroactivity_RetroActivityCommon_MODE_MULTI_PROCESS
|
||||||
|
#define com_retroarch_browser_retroactivity_RetroActivityCommon_MODE_MULTI_PROCESS 4L
|
||||||
|
#undef com_retroarch_browser_retroactivity_RetroActivityCommon_MODE_NO_LOCALIZED_COLLATORS
|
||||||
|
#define com_retroarch_browser_retroactivity_RetroActivityCommon_MODE_NO_LOCALIZED_COLLATORS 16L
|
||||||
|
#undef com_retroarch_browser_retroactivity_RetroActivityCommon_MODE_PRIVATE
|
||||||
|
#define com_retroarch_browser_retroactivity_RetroActivityCommon_MODE_PRIVATE 0L
|
||||||
|
#undef com_retroarch_browser_retroactivity_RetroActivityCommon_MODE_WORLD_READABLE
|
||||||
|
#define com_retroarch_browser_retroactivity_RetroActivityCommon_MODE_WORLD_READABLE 1L
|
||||||
|
#undef com_retroarch_browser_retroactivity_RetroActivityCommon_MODE_WORLD_WRITEABLE
|
||||||
|
#define com_retroarch_browser_retroactivity_RetroActivityCommon_MODE_WORLD_WRITEABLE 2L
|
||||||
|
#undef com_retroarch_browser_retroactivity_RetroActivityCommon_RECEIVER_VISIBLE_TO_INSTANT_APPS
|
||||||
|
#define com_retroarch_browser_retroactivity_RetroActivityCommon_RECEIVER_VISIBLE_TO_INSTANT_APPS 1L
|
||||||
|
#undef com_retroarch_browser_retroactivity_RetroActivityCommon_DEFAULT_KEYS_DIALER
|
||||||
|
#define com_retroarch_browser_retroactivity_RetroActivityCommon_DEFAULT_KEYS_DIALER 1L
|
||||||
|
#undef com_retroarch_browser_retroactivity_RetroActivityCommon_DEFAULT_KEYS_DISABLE
|
||||||
|
#define com_retroarch_browser_retroactivity_RetroActivityCommon_DEFAULT_KEYS_DISABLE 0L
|
||||||
|
#undef com_retroarch_browser_retroactivity_RetroActivityCommon_DEFAULT_KEYS_SEARCH_GLOBAL
|
||||||
|
#define com_retroarch_browser_retroactivity_RetroActivityCommon_DEFAULT_KEYS_SEARCH_GLOBAL 4L
|
||||||
|
#undef com_retroarch_browser_retroactivity_RetroActivityCommon_DEFAULT_KEYS_SEARCH_LOCAL
|
||||||
|
#define com_retroarch_browser_retroactivity_RetroActivityCommon_DEFAULT_KEYS_SEARCH_LOCAL 3L
|
||||||
|
#undef com_retroarch_browser_retroactivity_RetroActivityCommon_DEFAULT_KEYS_SHORTCUT
|
||||||
|
#define com_retroarch_browser_retroactivity_RetroActivityCommon_DEFAULT_KEYS_SHORTCUT 2L
|
||||||
|
#undef com_retroarch_browser_retroactivity_RetroActivityCommon_RESULT_CANCELED
|
||||||
|
#define com_retroarch_browser_retroactivity_RetroActivityCommon_RESULT_CANCELED 0L
|
||||||
|
#undef com_retroarch_browser_retroactivity_RetroActivityCommon_RESULT_FIRST_USER
|
||||||
|
#define com_retroarch_browser_retroactivity_RetroActivityCommon_RESULT_FIRST_USER 1L
|
||||||
|
#undef com_retroarch_browser_retroactivity_RetroActivityCommon_RESULT_OK
|
||||||
|
#define com_retroarch_browser_retroactivity_RetroActivityCommon_RESULT_OK -1L
|
||||||
|
/*
|
||||||
|
* Class: com_retroarch_browser_retroactivity_RetroActivityCommon
|
||||||
|
* Method: coreInstallInitiated
|
||||||
|
* Signature: (Ljava/lang/String;Z)V
|
||||||
|
*/
|
||||||
|
JNIEXPORT void JNICALL Java_com_retroarch_browser_retroactivity_RetroActivityCommon_coreInstallInitiated
|
||||||
|
(JNIEnv *, jobject, jstring, jboolean);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: com_retroarch_browser_retroactivity_RetroActivityCommon
|
||||||
|
* Method: coreInstallStatusChanged
|
||||||
|
* Signature: ([Ljava/lang/String;IJJ)V
|
||||||
|
*/
|
||||||
|
JNIEXPORT void JNICALL Java_com_retroarch_browser_retroactivity_RetroActivityCommon_coreInstallStatusChanged
|
||||||
|
(JNIEnv *, jobject, jobjectArray, jint, jlong, jlong);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
528
play_feature_delivery/play_feature_delivery.c
Normal file
528
play_feature_delivery/play_feature_delivery.c
Normal file
@ -0,0 +1,528 @@
|
|||||||
|
/* RetroArch - A frontend for libretro.
|
||||||
|
* Copyright (C) 2011-2017 - Daniel De Matteis
|
||||||
|
* Copyright (C) 2014-2017 - Jean-André Santoni
|
||||||
|
* Copyright (C) 2016-2019 - Brad Parker
|
||||||
|
* Copyright (C) 2019-2020 - James Leaver
|
||||||
|
*
|
||||||
|
* RetroArch 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 Found-
|
||||||
|
* ation, either version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* RetroArch 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 for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with RetroArch.
|
||||||
|
* If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "com_retroarch_browser_retroactivity_RetroActivityCommon.h"
|
||||||
|
|
||||||
|
#ifdef HAVE_THREADS
|
||||||
|
#include <rthreads/rthreads.h>
|
||||||
|
#include <retro_assert.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <string/stdstring.h>
|
||||||
|
#include "../frontend/drivers/platform_unix.h"
|
||||||
|
|
||||||
|
#include "play_feature_delivery.h"
|
||||||
|
|
||||||
|
/***************************/
|
||||||
|
/* Globals (do not fix...) */
|
||||||
|
/***************************/
|
||||||
|
|
||||||
|
/* Due to the way the JNI interface works,
|
||||||
|
* core download status updates happen
|
||||||
|
* asynchronously in a manner that we cannot
|
||||||
|
* capture using any standard means. We therefore
|
||||||
|
* have to implement status monitoring via an
|
||||||
|
* ugly hack, involving a mutex-locked global
|
||||||
|
* status struct... */
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
#ifdef HAVE_THREADS
|
||||||
|
slock_t *lock;
|
||||||
|
#endif
|
||||||
|
unsigned download_progress;
|
||||||
|
enum play_feature_delivery_install_status last_status;
|
||||||
|
char last_core_name[256];
|
||||||
|
bool active;
|
||||||
|
} play_feature_delivery_state_t;
|
||||||
|
|
||||||
|
static play_feature_delivery_state_t play_feature_delivery_state = {
|
||||||
|
|
||||||
|
#ifdef HAVE_THREADS
|
||||||
|
NULL, /* lock */
|
||||||
|
#endif
|
||||||
|
0, /* download_progress */
|
||||||
|
PLAY_FEATURE_DELIVERY_IDLE, /* last_status */
|
||||||
|
{'\0'}, /* last_core_name */
|
||||||
|
false, /* active */
|
||||||
|
};
|
||||||
|
|
||||||
|
static play_feature_delivery_state_t* play_feature_delivery_get_state(void)
|
||||||
|
{
|
||||||
|
return &play_feature_delivery_state;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**********************/
|
||||||
|
/* JNI Native Methods */
|
||||||
|
/**********************/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: com_retroarch_browser_retroactivity_RetroActivityCommon
|
||||||
|
* Method: coreInstallInitiated
|
||||||
|
* Signature: (Ljava/lang/String;Z)V
|
||||||
|
*/
|
||||||
|
JNIEXPORT void JNICALL Java_com_retroarch_browser_retroactivity_RetroActivityCommon_coreInstallInitiated
|
||||||
|
(JNIEnv *env, jobject this_obj, jstring core_name, jboolean successful)
|
||||||
|
{
|
||||||
|
play_feature_delivery_state_t* state = play_feature_delivery_get_state();
|
||||||
|
const char *core_name_c = NULL;
|
||||||
|
|
||||||
|
/* Lock mutex */
|
||||||
|
#ifdef HAVE_THREADS
|
||||||
|
slock_lock(state->lock);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Only update status if an install is active */
|
||||||
|
if (state->active)
|
||||||
|
{
|
||||||
|
/* Convert Java-style string to a proper char array */
|
||||||
|
const char *core_name_c = (*env)->GetStringUTFChars(
|
||||||
|
env, core_name, NULL);
|
||||||
|
|
||||||
|
/* Ensure that status update is for the
|
||||||
|
* correct core */
|
||||||
|
if (string_is_equal(state->last_core_name, core_name_c))
|
||||||
|
{
|
||||||
|
if (successful)
|
||||||
|
state->last_status = PLAY_FEATURE_DELIVERY_STARTING;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
state->last_status = PLAY_FEATURE_DELIVERY_FAILED;
|
||||||
|
state->active = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Must always 'release' the converted string */
|
||||||
|
(*env)->ReleaseStringUTFChars(env, core_name, core_name_c);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Unlock mutex */
|
||||||
|
#ifdef HAVE_THREADS
|
||||||
|
slock_unlock(state->lock);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: com_retroarch_browser_retroactivity_RetroActivityCommon
|
||||||
|
* Method: coreInstallStatusChanged
|
||||||
|
* Signature: ([Ljava/lang/String;IJJ)V
|
||||||
|
*/
|
||||||
|
JNIEXPORT void JNICALL Java_com_retroarch_browser_retroactivity_RetroActivityCommon_coreInstallStatusChanged
|
||||||
|
(JNIEnv *env, jobject thisObj, jobjectArray core_names, jint status, jlong bytes_downloaded, jlong total_bytes_to_download)
|
||||||
|
{
|
||||||
|
play_feature_delivery_state_t* state = play_feature_delivery_get_state();
|
||||||
|
|
||||||
|
/* Lock mutex */
|
||||||
|
#ifdef HAVE_THREADS
|
||||||
|
slock_lock(state->lock);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Only update status if an install is active */
|
||||||
|
if (state->active)
|
||||||
|
{
|
||||||
|
/* Note: core_names is a list of cores that
|
||||||
|
* are currently installing. We should check
|
||||||
|
* that state->last_core_name is in this list
|
||||||
|
* before updating the status, but if multiple
|
||||||
|
* installs are queued then it seems dubious
|
||||||
|
* to filter like this - i.e. is it possible
|
||||||
|
* for an entry to drop off the queue before
|
||||||
|
* the entire transaction is complete? If so,
|
||||||
|
* then we may risk 'missing' the final status
|
||||||
|
* update...
|
||||||
|
* We therefore just monitor the transaction
|
||||||
|
* as a whole, and disregard core names... */
|
||||||
|
|
||||||
|
/* Determine download progress */
|
||||||
|
if (total_bytes_to_download > 0)
|
||||||
|
{
|
||||||
|
state->download_progress = (unsigned)
|
||||||
|
(((float)bytes_downloaded * 100.0f /
|
||||||
|
(float)total_bytes_to_download) + 0.5f);
|
||||||
|
state->download_progress = (state->download_progress > 100) ?
|
||||||
|
100 : state->download_progress;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
state->download_progress = 100;
|
||||||
|
|
||||||
|
/* Check status */
|
||||||
|
switch (status)
|
||||||
|
{
|
||||||
|
case 0: /* INSTALL_STATUS_DOWNLOADING */
|
||||||
|
state->last_status = PLAY_FEATURE_DELIVERY_DOWNLOADING;
|
||||||
|
break;
|
||||||
|
case 1: /* INSTALL_STATUS_INSTALLING */
|
||||||
|
state->last_status = PLAY_FEATURE_DELIVERY_INSTALLING;
|
||||||
|
break;
|
||||||
|
case 2: /* INSTALL_STATUS_INSTALLED */
|
||||||
|
state->last_status = PLAY_FEATURE_DELIVERY_INSTALLED;
|
||||||
|
state->active = false;
|
||||||
|
break;
|
||||||
|
case 3: /* INSTALL_STATUS_FAILED */
|
||||||
|
default:
|
||||||
|
state->last_status = PLAY_FEATURE_DELIVERY_FAILED;
|
||||||
|
state->active = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Unlock mutex */
|
||||||
|
#ifdef HAVE_THREADS
|
||||||
|
slock_unlock(state->lock);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************/
|
||||||
|
/* Initialisation */
|
||||||
|
/******************/
|
||||||
|
|
||||||
|
/* Must be called upon program initialisation */
|
||||||
|
void play_feature_delivery_init(void)
|
||||||
|
{
|
||||||
|
play_feature_delivery_state_t* state = play_feature_delivery_get_state();
|
||||||
|
|
||||||
|
play_feature_delivery_deinit();
|
||||||
|
#ifdef HAVE_THREADS
|
||||||
|
if (!state->lock)
|
||||||
|
state->lock = slock_new();
|
||||||
|
|
||||||
|
retro_assert(state->lock);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Must be called upon program termination */
|
||||||
|
void play_feature_delivery_deinit(void)
|
||||||
|
{
|
||||||
|
play_feature_delivery_state_t* state = play_feature_delivery_get_state();
|
||||||
|
|
||||||
|
#ifdef HAVE_THREADS
|
||||||
|
if (state->lock)
|
||||||
|
{
|
||||||
|
slock_free(state->lock);
|
||||||
|
state->lock = NULL;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/**********/
|
||||||
|
/* Status */
|
||||||
|
/**********/
|
||||||
|
|
||||||
|
static bool play_feature_delivery_get_core_name(
|
||||||
|
const char *core_file, char *core_name, size_t len)
|
||||||
|
{
|
||||||
|
size_t core_file_len;
|
||||||
|
|
||||||
|
if (string_is_empty(core_file))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
core_file_len = strlen(core_file);
|
||||||
|
|
||||||
|
if (len < core_file_len)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* Ensure that core_file has the correct
|
||||||
|
* suffix */
|
||||||
|
if (!string_ends_with_size(core_file, "_libretro_android.so",
|
||||||
|
core_file_len, STRLEN_CONST("_libretro_android.so")))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* Copy core_file and remove suffix */
|
||||||
|
strlcpy(core_name, core_file, len);
|
||||||
|
core_name[core_file_len - STRLEN_CONST("_libretro_android.so")] = '\0';
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returns true if current build utilises
|
||||||
|
* play feature delivery */
|
||||||
|
bool play_feature_delivery_enabled(void)
|
||||||
|
{
|
||||||
|
JNIEnv *env = jni_thread_getenv();
|
||||||
|
struct android_app *app = (struct android_app*)g_android;
|
||||||
|
bool enabled = false;
|
||||||
|
|
||||||
|
if (!env ||
|
||||||
|
!app ||
|
||||||
|
!app->isPlayStoreBuild)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
CALL_BOOLEAN_METHOD(env, enabled, app->activity->clazz,
|
||||||
|
app->isPlayStoreBuild);
|
||||||
|
|
||||||
|
return enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returns a list of cores currently available
|
||||||
|
* via play feature delivery.
|
||||||
|
* Returns a new string_list on success, or
|
||||||
|
* NULL on failure */
|
||||||
|
struct string_list *play_feature_delivery_available_cores(void)
|
||||||
|
{
|
||||||
|
JNIEnv *env = jni_thread_getenv();
|
||||||
|
struct android_app *app = (struct android_app*)g_android;
|
||||||
|
struct string_list *core_list = string_list_new();
|
||||||
|
union string_list_elem_attr attr;
|
||||||
|
jobjectArray available_cores;
|
||||||
|
jsize num_cores;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
attr.i = 0;
|
||||||
|
|
||||||
|
if (!env ||
|
||||||
|
!app ||
|
||||||
|
!app->getAvailableCores ||
|
||||||
|
!core_list)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
/* Get list of available cores */
|
||||||
|
CALL_OBJ_METHOD(env, available_cores, app->activity->clazz,
|
||||||
|
app->getAvailableCores);
|
||||||
|
num_cores = (*env)->GetArrayLength(env, available_cores);
|
||||||
|
|
||||||
|
for (i = 0; i < num_cores; i++)
|
||||||
|
{
|
||||||
|
/* Extract element of available cores array */
|
||||||
|
jstring core_name_jni = (jstring)
|
||||||
|
((*env)->GetObjectArrayElement(env, available_cores, i));
|
||||||
|
const char *core_name = NULL;
|
||||||
|
|
||||||
|
/* Convert Java-style string to a proper char array */
|
||||||
|
core_name = (*env)->GetStringUTFChars(env, core_name_jni, NULL);
|
||||||
|
|
||||||
|
if (!string_is_empty(core_name))
|
||||||
|
{
|
||||||
|
char core_file[256];
|
||||||
|
core_file[0] = '\0';
|
||||||
|
|
||||||
|
/* Generate core file name */
|
||||||
|
strlcpy(core_file, core_name, sizeof(core_file));
|
||||||
|
strlcat(core_file, "_libretro_android.so", sizeof(core_file));
|
||||||
|
|
||||||
|
/* Add entry to list */
|
||||||
|
if (!string_is_empty(core_file))
|
||||||
|
string_list_append(core_list, core_file, attr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Must always 'release' the converted string */
|
||||||
|
(*env)->ReleaseStringUTFChars(env, core_name_jni, core_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (core_list->size < 1)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
return core_list;
|
||||||
|
|
||||||
|
error:
|
||||||
|
if (core_list)
|
||||||
|
string_list_free(core_list);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returns true if specified core is currently
|
||||||
|
* installed via play feature delivery */
|
||||||
|
bool play_feature_delivery_core_installed(const char *core_file)
|
||||||
|
{
|
||||||
|
JNIEnv *env = jni_thread_getenv();
|
||||||
|
struct android_app *app = (struct android_app*)g_android;
|
||||||
|
jobjectArray installed_cores;
|
||||||
|
jsize num_cores;
|
||||||
|
char core_name[256];
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
core_name[0] = '\0';
|
||||||
|
|
||||||
|
if (!env ||
|
||||||
|
!app ||
|
||||||
|
!app->getInstalledCores)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* Extract core name */
|
||||||
|
if (!play_feature_delivery_get_core_name(
|
||||||
|
core_file, core_name, sizeof(core_name)))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* Get list of installed cores */
|
||||||
|
CALL_OBJ_METHOD(env, installed_cores, app->activity->clazz,
|
||||||
|
app->getInstalledCores);
|
||||||
|
num_cores = (*env)->GetArrayLength(env, installed_cores);
|
||||||
|
|
||||||
|
for (i = 0; i < num_cores; i++)
|
||||||
|
{
|
||||||
|
/* Extract element of installed cores array */
|
||||||
|
jstring installed_core_name_jni = (jstring)
|
||||||
|
((*env)->GetObjectArrayElement(env, installed_cores, i));
|
||||||
|
const char *installed_core_name = NULL;
|
||||||
|
|
||||||
|
/* Convert Java-style string to a proper char array */
|
||||||
|
installed_core_name = (*env)->GetStringUTFChars(
|
||||||
|
env, installed_core_name_jni, NULL);
|
||||||
|
|
||||||
|
/* Check for a match */
|
||||||
|
if (!string_is_empty(installed_core_name) &&
|
||||||
|
string_is_equal(core_name, installed_core_name))
|
||||||
|
{
|
||||||
|
/* Must always 'release' the converted string */
|
||||||
|
(*env)->ReleaseStringUTFChars(env,
|
||||||
|
installed_core_name_jni, installed_core_name);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Must always 'release' the converted string */
|
||||||
|
(*env)->ReleaseStringUTFChars(env,
|
||||||
|
installed_core_name_jni, installed_core_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fetches last recorded status of the most
|
||||||
|
* recently initiated play feature delivery
|
||||||
|
* install transaction.
|
||||||
|
* 'progress' is an integer from 0-100.
|
||||||
|
* Returns true if a transaction is currently
|
||||||
|
* in progress. */
|
||||||
|
bool play_feature_delivery_download_status(
|
||||||
|
enum play_feature_delivery_install_status *status,
|
||||||
|
unsigned *progress)
|
||||||
|
{
|
||||||
|
play_feature_delivery_state_t* state = play_feature_delivery_get_state();
|
||||||
|
bool active;
|
||||||
|
|
||||||
|
/* Lock mutex */
|
||||||
|
#ifdef HAVE_THREADS
|
||||||
|
slock_lock(state->lock);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Copy status parameters */
|
||||||
|
if (status)
|
||||||
|
*status = state->last_status;
|
||||||
|
|
||||||
|
if (progress)
|
||||||
|
*progress = state->download_progress;
|
||||||
|
|
||||||
|
active = state->active;
|
||||||
|
|
||||||
|
/* Unlock mutex */
|
||||||
|
#ifdef HAVE_THREADS
|
||||||
|
slock_unlock(state->lock);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return active;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***********/
|
||||||
|
/* Control */
|
||||||
|
/***********/
|
||||||
|
|
||||||
|
/* Initialises download of the specified core.
|
||||||
|
* Returns false in the event of an error.
|
||||||
|
* Download status should be monitored via
|
||||||
|
* play_feature_delivery_download_status() */
|
||||||
|
bool play_feature_delivery_download(const char *core_file)
|
||||||
|
{
|
||||||
|
play_feature_delivery_state_t* state = play_feature_delivery_get_state();
|
||||||
|
JNIEnv *env = jni_thread_getenv();
|
||||||
|
struct android_app *app = (struct android_app*)g_android;
|
||||||
|
bool success = false;
|
||||||
|
char core_name[256];
|
||||||
|
jstring core_name_jni;
|
||||||
|
|
||||||
|
core_name[0] = '\0';
|
||||||
|
|
||||||
|
if (!env ||
|
||||||
|
!app ||
|
||||||
|
!app->downloadCore)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* Extract core name */
|
||||||
|
if (!play_feature_delivery_get_core_name(
|
||||||
|
core_file, core_name, sizeof(core_name)))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* Lock mutex */
|
||||||
|
#ifdef HAVE_THREADS
|
||||||
|
slock_lock(state->lock);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* We only support one download at a time */
|
||||||
|
if (!state->active)
|
||||||
|
{
|
||||||
|
/* Convert to a Java-style string */
|
||||||
|
core_name_jni = (*env)->NewStringUTF(env, core_name);
|
||||||
|
|
||||||
|
/* Request download */
|
||||||
|
CALL_VOID_METHOD_PARAM(env, app->activity->clazz,
|
||||||
|
app->downloadCore, core_name_jni);
|
||||||
|
|
||||||
|
/* Free core_name_jni reference */
|
||||||
|
(*env)->DeleteLocalRef(env, core_name_jni);
|
||||||
|
|
||||||
|
/* Update status */
|
||||||
|
state->download_progress = 0;
|
||||||
|
state->last_status = PLAY_FEATURE_DELIVERY_PENDING;
|
||||||
|
state->active = true;
|
||||||
|
strlcpy(state->last_core_name, core_name,
|
||||||
|
sizeof(state->last_core_name));
|
||||||
|
|
||||||
|
success = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Unlock mutex */
|
||||||
|
#ifdef HAVE_THREADS
|
||||||
|
slock_unlock(state->lock);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Deletes specified core.
|
||||||
|
* Returns false in the event of an error. */
|
||||||
|
bool play_feature_delivery_delete(const char *core_file)
|
||||||
|
{
|
||||||
|
JNIEnv *env = jni_thread_getenv();
|
||||||
|
struct android_app *app = (struct android_app*)g_android;
|
||||||
|
char core_name[256];
|
||||||
|
jstring core_name_jni;
|
||||||
|
|
||||||
|
core_name[0] = '\0';
|
||||||
|
|
||||||
|
if (!env ||
|
||||||
|
!app ||
|
||||||
|
!app->deleteCore)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* Extract core name */
|
||||||
|
if (!play_feature_delivery_get_core_name(
|
||||||
|
core_file, core_name, sizeof(core_name)))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* Convert to a Java-style string */
|
||||||
|
core_name_jni = (*env)->NewStringUTF(env, core_name);
|
||||||
|
|
||||||
|
/* Request core deletion */
|
||||||
|
CALL_VOID_METHOD_PARAM(env, app->activity->clazz,
|
||||||
|
app->deleteCore, core_name_jni);
|
||||||
|
|
||||||
|
/* Free core_name_jni reference */
|
||||||
|
(*env)->DeleteLocalRef(env, core_name_jni);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
99
play_feature_delivery/play_feature_delivery.h
Normal file
99
play_feature_delivery/play_feature_delivery.h
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
/* RetroArch - A frontend for libretro.
|
||||||
|
* Copyright (C) 2011-2017 - Daniel De Matteis
|
||||||
|
* Copyright (C) 2014-2017 - Jean-André Santoni
|
||||||
|
* Copyright (C) 2016-2019 - Brad Parker
|
||||||
|
* Copyright (C) 2019-2020 - James Leaver
|
||||||
|
*
|
||||||
|
* RetroArch 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 Found-
|
||||||
|
* ation, either version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* RetroArch 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 for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with RetroArch.
|
||||||
|
* If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __PLAY_FEATURE_DELIVERY_H
|
||||||
|
#define __PLAY_FEATURE_DELIVERY_H
|
||||||
|
|
||||||
|
#include <retro_common_api.h>
|
||||||
|
#include <libretro.h>
|
||||||
|
|
||||||
|
#include <lists/string_list.h>
|
||||||
|
|
||||||
|
#include <boolean.h>
|
||||||
|
|
||||||
|
RETRO_BEGIN_DECLS
|
||||||
|
|
||||||
|
/* Defines possible status values of
|
||||||
|
* a play feature delivery install
|
||||||
|
* transaction */
|
||||||
|
enum play_feature_delivery_install_status
|
||||||
|
{
|
||||||
|
PLAY_FEATURE_DELIVERY_IDLE = 0,
|
||||||
|
PLAY_FEATURE_DELIVERY_PENDING,
|
||||||
|
PLAY_FEATURE_DELIVERY_STARTING,
|
||||||
|
PLAY_FEATURE_DELIVERY_DOWNLOADING,
|
||||||
|
PLAY_FEATURE_DELIVERY_INSTALLING,
|
||||||
|
PLAY_FEATURE_DELIVERY_INSTALLED,
|
||||||
|
PLAY_FEATURE_DELIVERY_FAILED
|
||||||
|
};
|
||||||
|
|
||||||
|
/******************/
|
||||||
|
/* Initialisation */
|
||||||
|
/******************/
|
||||||
|
|
||||||
|
/* Must be called upon program initialisation */
|
||||||
|
void play_feature_delivery_init(void);
|
||||||
|
|
||||||
|
/* Must be called upon program termination */
|
||||||
|
void play_feature_delivery_deinit(void);
|
||||||
|
|
||||||
|
/**********/
|
||||||
|
/* Status */
|
||||||
|
/**********/
|
||||||
|
|
||||||
|
/* Returns true if current build utilises
|
||||||
|
* play feature delivery */
|
||||||
|
bool play_feature_delivery_enabled(void);
|
||||||
|
|
||||||
|
/* Returns a list of cores currently available
|
||||||
|
* via play feature delivery.
|
||||||
|
* Returns a new string_list on success, or
|
||||||
|
* NULL on failure */
|
||||||
|
struct string_list *play_feature_delivery_available_cores(void);
|
||||||
|
|
||||||
|
/* Returns true if specified core is currently
|
||||||
|
* installed via play feature delivery */
|
||||||
|
bool play_feature_delivery_core_installed(const char *core_file);
|
||||||
|
|
||||||
|
/* Fetches last recorded status of the most
|
||||||
|
* recently initiated play feature delivery
|
||||||
|
* install transaction.
|
||||||
|
* 'progress' is an integer from 0-100.
|
||||||
|
* Returns true if a transaction is currently
|
||||||
|
* in progress. */
|
||||||
|
bool play_feature_delivery_download_status(
|
||||||
|
enum play_feature_delivery_install_status *status,
|
||||||
|
unsigned *progress);
|
||||||
|
|
||||||
|
/***********/
|
||||||
|
/* Control */
|
||||||
|
/***********/
|
||||||
|
|
||||||
|
/* Initialises download of the specified core.
|
||||||
|
* Returns false in the event of an error.
|
||||||
|
* Download status should be monitored via
|
||||||
|
* play_feature_delivery_download_status() */
|
||||||
|
bool play_feature_delivery_download(const char *core_file);
|
||||||
|
|
||||||
|
/* Deletes specified core.
|
||||||
|
* Returns false in the event of an error. */
|
||||||
|
bool play_feature_delivery_delete(const char *core_file);
|
||||||
|
|
||||||
|
RETRO_END_DECLS
|
||||||
|
|
||||||
|
#endif
|
12
retroarch.c
12
retroarch.c
@ -120,6 +120,10 @@
|
|||||||
#include "switch_performance_profiles.h"
|
#include "switch_performance_profiles.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(ANDROID)
|
||||||
|
#include "play_feature_delivery/play_feature_delivery.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_DISCORD
|
#ifdef HAVE_DISCORD
|
||||||
#include <discord_rpc.h>
|
#include <discord_rpc.h>
|
||||||
#include "deps/discord-rpc/include/discord_rpc.h"
|
#include "deps/discord-rpc/include/discord_rpc.h"
|
||||||
@ -17539,6 +17543,10 @@ void main_exit(void *args)
|
|||||||
|
|
||||||
rtime_deinit();
|
rtime_deinit();
|
||||||
|
|
||||||
|
#if defined(ANDROID)
|
||||||
|
play_feature_delivery_deinit();
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(_WIN32) && !defined(_XBOX) && !defined(__WINRT__)
|
#if defined(_WIN32) && !defined(_XBOX) && !defined(__WINRT__)
|
||||||
CoUninitialize();
|
CoUninitialize();
|
||||||
#endif
|
#endif
|
||||||
@ -17577,6 +17585,10 @@ int rarch_main(int argc, char *argv[], void *data)
|
|||||||
|
|
||||||
rtime_init();
|
rtime_init();
|
||||||
|
|
||||||
|
#if defined(ANDROID)
|
||||||
|
play_feature_delivery_init();
|
||||||
|
#endif
|
||||||
|
|
||||||
libretro_free_system_info(&p_rarch->runloop_system.info);
|
libretro_free_system_info(&p_rarch->runloop_system.info);
|
||||||
command_event(CMD_EVENT_HISTORY_DEINIT, NULL);
|
command_event(CMD_EVENT_HISTORY_DEINIT, NULL);
|
||||||
rarch_favorites_deinit();
|
rarch_favorites_deinit();
|
||||||
|
@ -36,6 +36,10 @@
|
|||||||
#include "../core_info.h"
|
#include "../core_info.h"
|
||||||
#include "../core_backup.h"
|
#include "../core_backup.h"
|
||||||
|
|
||||||
|
#if defined(ANDROID)
|
||||||
|
#include "../play_feature_delivery/play_feature_delivery.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#define CORE_BACKUP_CHUNK_SIZE 4096
|
#define CORE_BACKUP_CHUNK_SIZE 4096
|
||||||
|
|
||||||
enum core_backup_status
|
enum core_backup_status
|
||||||
@ -778,6 +782,27 @@ static void task_core_restore_handler(retro_task_t *task)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(ANDROID)
|
||||||
|
/* If this is a Play Store build and the
|
||||||
|
* core is currently installed via
|
||||||
|
* play feature delivery, must delete
|
||||||
|
* the existing core before attempting
|
||||||
|
* to write any data */
|
||||||
|
if (play_feature_delivery_enabled())
|
||||||
|
{
|
||||||
|
const char *core_filename = path_basename(
|
||||||
|
backup_handle->core_path);
|
||||||
|
|
||||||
|
if (play_feature_delivery_core_installed(core_filename) &&
|
||||||
|
!play_feature_delivery_delete(core_filename))
|
||||||
|
{
|
||||||
|
RARCH_ERR("[core restore] Failed to delete existing play feature delivery core: %s\n",
|
||||||
|
backup_handle->core_path);
|
||||||
|
backup_handle->status = CORE_RESTORE_END;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
/* Open core file for writing */
|
/* Open core file for writing */
|
||||||
backup_handle->core_file = intfstream_open_file(
|
backup_handle->core_file = intfstream_open_file(
|
||||||
backup_handle->core_path, RETRO_VFS_FILE_ACCESS_WRITE,
|
backup_handle->core_path, RETRO_VFS_FILE_ACCESS_WRITE,
|
||||||
|
@ -38,6 +38,10 @@
|
|||||||
#include "../verbosity.h"
|
#include "../verbosity.h"
|
||||||
#include "../core_updater_list.h"
|
#include "../core_updater_list.h"
|
||||||
|
|
||||||
|
#if defined(ANDROID)
|
||||||
|
#include "../play_feature_delivery/play_feature_delivery.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(RARCH_INTERNAL) && defined(HAVE_MENU)
|
#if defined(RARCH_INTERNAL) && defined(HAVE_MENU)
|
||||||
#include "../menu/menu_entries.h"
|
#include "../menu/menu_entries.h"
|
||||||
#endif
|
#endif
|
||||||
@ -50,29 +54,6 @@ enum core_updater_list_status
|
|||||||
CORE_UPDATER_LIST_END
|
CORE_UPDATER_LIST_END
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Download core */
|
|
||||||
enum core_updater_download_status
|
|
||||||
{
|
|
||||||
CORE_UPDATER_DOWNLOAD_BEGIN = 0,
|
|
||||||
CORE_UPDATER_DOWNLOAD_START_BACKUP,
|
|
||||||
CORE_UPDATER_DOWNLOAD_WAIT_BACKUP,
|
|
||||||
CORE_UPDATER_DOWNLOAD_START_TRANSFER,
|
|
||||||
CORE_UPDATER_DOWNLOAD_WAIT_TRANSFER,
|
|
||||||
CORE_UPDATER_DOWNLOAD_WAIT_DECOMPRESS,
|
|
||||||
CORE_UPDATER_DOWNLOAD_END
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Update installed cores */
|
|
||||||
enum update_installed_cores_status
|
|
||||||
{
|
|
||||||
UPDATE_INSTALLED_CORES_BEGIN = 0,
|
|
||||||
UPDATE_INSTALLED_CORES_WAIT_LIST,
|
|
||||||
UPDATE_INSTALLED_CORES_ITERATE,
|
|
||||||
UPDATE_INSTALLED_CORES_UPDATE_CORE,
|
|
||||||
UPDATE_INSTALLED_CORES_WAIT_DOWNLOAD,
|
|
||||||
UPDATE_INSTALLED_CORES_END
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct core_updater_list_handle
|
typedef struct core_updater_list_handle
|
||||||
{
|
{
|
||||||
core_updater_list_t* core_list;
|
core_updater_list_t* core_list;
|
||||||
@ -85,6 +66,18 @@ typedef struct core_updater_list_handle
|
|||||||
bool http_task_success;
|
bool http_task_success;
|
||||||
} core_updater_list_handle_t;
|
} core_updater_list_handle_t;
|
||||||
|
|
||||||
|
/* Download core */
|
||||||
|
enum core_updater_download_status
|
||||||
|
{
|
||||||
|
CORE_UPDATER_DOWNLOAD_BEGIN = 0,
|
||||||
|
CORE_UPDATER_DOWNLOAD_START_BACKUP,
|
||||||
|
CORE_UPDATER_DOWNLOAD_WAIT_BACKUP,
|
||||||
|
CORE_UPDATER_DOWNLOAD_START_TRANSFER,
|
||||||
|
CORE_UPDATER_DOWNLOAD_WAIT_TRANSFER,
|
||||||
|
CORE_UPDATER_DOWNLOAD_WAIT_DECOMPRESS,
|
||||||
|
CORE_UPDATER_DOWNLOAD_END
|
||||||
|
};
|
||||||
|
|
||||||
typedef struct core_updater_download_handle
|
typedef struct core_updater_download_handle
|
||||||
{
|
{
|
||||||
char *path_dir_libretro;
|
char *path_dir_libretro;
|
||||||
@ -110,6 +103,17 @@ typedef struct core_updater_download_handle
|
|||||||
bool backup_enabled;
|
bool backup_enabled;
|
||||||
} core_updater_download_handle_t;
|
} core_updater_download_handle_t;
|
||||||
|
|
||||||
|
/* Update installed cores */
|
||||||
|
enum update_installed_cores_status
|
||||||
|
{
|
||||||
|
UPDATE_INSTALLED_CORES_BEGIN = 0,
|
||||||
|
UPDATE_INSTALLED_CORES_WAIT_LIST,
|
||||||
|
UPDATE_INSTALLED_CORES_ITERATE,
|
||||||
|
UPDATE_INSTALLED_CORES_UPDATE_CORE,
|
||||||
|
UPDATE_INSTALLED_CORES_WAIT_DOWNLOAD,
|
||||||
|
UPDATE_INSTALLED_CORES_END
|
||||||
|
};
|
||||||
|
|
||||||
typedef struct update_installed_cores_handle
|
typedef struct update_installed_cores_handle
|
||||||
{
|
{
|
||||||
char *path_dir_libretro;
|
char *path_dir_libretro;
|
||||||
@ -127,6 +131,26 @@ typedef struct update_installed_cores_handle
|
|||||||
bool auto_backup;
|
bool auto_backup;
|
||||||
} update_installed_cores_handle_t;
|
} update_installed_cores_handle_t;
|
||||||
|
|
||||||
|
/* Play feature delivery core install */
|
||||||
|
#if defined(ANDROID)
|
||||||
|
enum play_feature_delivery_install_task_status
|
||||||
|
{
|
||||||
|
PLAY_FEATURE_DELIVERY_INSTALL_BEGIN = 0,
|
||||||
|
PLAY_FEATURE_DELIVERY_INSTALL_WAIT,
|
||||||
|
PLAY_FEATURE_DELIVERY_INSTALL_END
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct play_feature_delivery_install_handle
|
||||||
|
{
|
||||||
|
char *core_filename;
|
||||||
|
char *local_core_path;
|
||||||
|
char *display_name;
|
||||||
|
enum play_feature_delivery_install_task_status status;
|
||||||
|
bool success;
|
||||||
|
bool core_already_installed;
|
||||||
|
} play_feature_delivery_install_handle_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
/*********************/
|
/*********************/
|
||||||
/* Utility functions */
|
/* Utility functions */
|
||||||
/*********************/
|
/*********************/
|
||||||
@ -393,6 +417,13 @@ void *task_push_get_core_updater_list(
|
|||||||
core_updater_list_handle_t *list_handle = (core_updater_list_handle_t*)
|
core_updater_list_handle_t *list_handle = (core_updater_list_handle_t*)
|
||||||
calloc(1, sizeof(core_updater_list_handle_t));
|
calloc(1, sizeof(core_updater_list_handle_t));
|
||||||
|
|
||||||
|
#if defined(ANDROID)
|
||||||
|
/* Regular core updater is disabled in
|
||||||
|
* Play Store builds */
|
||||||
|
if (play_feature_delivery_enabled())
|
||||||
|
goto error;
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Sanity check */
|
/* Sanity check */
|
||||||
if (!core_list || !list_handle)
|
if (!core_list || !list_handle)
|
||||||
goto error;
|
goto error;
|
||||||
@ -952,6 +983,13 @@ void *task_push_core_updater_download(
|
|||||||
task_title[0] = '\0';
|
task_title[0] = '\0';
|
||||||
local_download_path[0] = '\0';
|
local_download_path[0] = '\0';
|
||||||
|
|
||||||
|
#if defined(ANDROID)
|
||||||
|
/* Regular core updater is disabled in
|
||||||
|
* Play Store builds */
|
||||||
|
if (play_feature_delivery_enabled())
|
||||||
|
goto error;
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Sanity check */
|
/* Sanity check */
|
||||||
if (!core_list ||
|
if (!core_list ||
|
||||||
string_is_empty(filename) ||
|
string_is_empty(filename) ||
|
||||||
@ -1410,6 +1448,13 @@ void task_push_update_installed_cores(
|
|||||||
(update_installed_cores_handle_t*)
|
(update_installed_cores_handle_t*)
|
||||||
calloc(1, sizeof(update_installed_cores_handle_t));
|
calloc(1, sizeof(update_installed_cores_handle_t));
|
||||||
|
|
||||||
|
#if defined(ANDROID)
|
||||||
|
/* Regular core updater is disabled in
|
||||||
|
* Play Store builds */
|
||||||
|
if (play_feature_delivery_enabled())
|
||||||
|
goto error;
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Sanity check */
|
/* Sanity check */
|
||||||
if (!update_installed_handle ||
|
if (!update_installed_handle ||
|
||||||
string_is_empty(path_dir_libretro))
|
string_is_empty(path_dir_libretro))
|
||||||
@ -1471,3 +1516,265 @@ error:
|
|||||||
/* Clean up handle */
|
/* Clean up handle */
|
||||||
free_update_installed_cores_handle(update_installed_handle);
|
free_update_installed_cores_handle(update_installed_handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**************************************/
|
||||||
|
/* Play feature delivery core install */
|
||||||
|
/**************************************/
|
||||||
|
|
||||||
|
#if defined(ANDROID)
|
||||||
|
|
||||||
|
static void free_play_feature_delivery_install_handle(
|
||||||
|
play_feature_delivery_install_handle_t *pfd_install_handle)
|
||||||
|
{
|
||||||
|
if (!pfd_install_handle)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (pfd_install_handle->core_filename)
|
||||||
|
free(pfd_install_handle->core_filename);
|
||||||
|
|
||||||
|
if (pfd_install_handle->local_core_path)
|
||||||
|
free(pfd_install_handle->local_core_path);
|
||||||
|
|
||||||
|
if (pfd_install_handle->display_name)
|
||||||
|
free(pfd_install_handle->display_name);
|
||||||
|
|
||||||
|
free(pfd_install_handle);
|
||||||
|
pfd_install_handle = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void task_play_feature_delivery_core_install_handler(retro_task_t *task)
|
||||||
|
{
|
||||||
|
play_feature_delivery_install_handle_t *pfd_install_handle = NULL;
|
||||||
|
|
||||||
|
if (!task)
|
||||||
|
goto task_finished;
|
||||||
|
|
||||||
|
pfd_install_handle = (play_feature_delivery_install_handle_t*)task->state;
|
||||||
|
|
||||||
|
if (!pfd_install_handle)
|
||||||
|
goto task_finished;
|
||||||
|
|
||||||
|
if (task_get_cancelled(task))
|
||||||
|
goto task_finished;
|
||||||
|
|
||||||
|
switch (pfd_install_handle->status)
|
||||||
|
{
|
||||||
|
case PLAY_FEATURE_DELIVERY_INSTALL_BEGIN:
|
||||||
|
{
|
||||||
|
/* Check whether core has already been
|
||||||
|
* installed via play feature delivery */
|
||||||
|
if (play_feature_delivery_core_installed(
|
||||||
|
pfd_install_handle->core_filename))
|
||||||
|
{
|
||||||
|
pfd_install_handle->success = true;
|
||||||
|
pfd_install_handle->core_already_installed = true;
|
||||||
|
pfd_install_handle->status =
|
||||||
|
PLAY_FEATURE_DELIVERY_INSTALL_END;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If core is already installed via other
|
||||||
|
* means, must delete it before attempting
|
||||||
|
* play feature delivery transaction */
|
||||||
|
if (path_is_valid(pfd_install_handle->local_core_path))
|
||||||
|
filestream_delete(pfd_install_handle->local_core_path);
|
||||||
|
|
||||||
|
/* Start download */
|
||||||
|
if (play_feature_delivery_download(
|
||||||
|
pfd_install_handle->core_filename))
|
||||||
|
pfd_install_handle->status = PLAY_FEATURE_DELIVERY_INSTALL_WAIT;
|
||||||
|
else
|
||||||
|
pfd_install_handle->status = PLAY_FEATURE_DELIVERY_INSTALL_END;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case PLAY_FEATURE_DELIVERY_INSTALL_WAIT:
|
||||||
|
{
|
||||||
|
bool install_active;
|
||||||
|
enum play_feature_delivery_install_status install_status;
|
||||||
|
unsigned install_progress;
|
||||||
|
char task_title[PATH_MAX_LENGTH];
|
||||||
|
|
||||||
|
task_title[0] = '\0';
|
||||||
|
|
||||||
|
/* Get current install status */
|
||||||
|
install_active = play_feature_delivery_download_status(
|
||||||
|
&install_status, &install_progress);
|
||||||
|
|
||||||
|
/* In all cases, update task progress */
|
||||||
|
task_set_progress(task, install_progress);
|
||||||
|
|
||||||
|
/* Interpret status */
|
||||||
|
switch (install_status)
|
||||||
|
{
|
||||||
|
case PLAY_FEATURE_DELIVERY_INSTALLED:
|
||||||
|
pfd_install_handle->success = true;
|
||||||
|
pfd_install_handle->status = PLAY_FEATURE_DELIVERY_INSTALL_END;
|
||||||
|
break;
|
||||||
|
case PLAY_FEATURE_DELIVERY_FAILED:
|
||||||
|
pfd_install_handle->status = PLAY_FEATURE_DELIVERY_INSTALL_END;
|
||||||
|
break;
|
||||||
|
case PLAY_FEATURE_DELIVERY_DOWNLOADING:
|
||||||
|
task_free_title(task);
|
||||||
|
strlcpy(task_title, msg_hash_to_str(MSG_DOWNLOADING_CORE),
|
||||||
|
sizeof(task_title));
|
||||||
|
strlcat(task_title, pfd_install_handle->display_name,
|
||||||
|
sizeof(task_title));
|
||||||
|
task_set_title(task, strdup(task_title));
|
||||||
|
break;
|
||||||
|
case PLAY_FEATURE_DELIVERY_INSTALLING:
|
||||||
|
task_free_title(task);
|
||||||
|
strlcpy(task_title, msg_hash_to_str(MSG_INSTALLING_CORE),
|
||||||
|
sizeof(task_title));
|
||||||
|
strlcat(task_title, pfd_install_handle->display_name,
|
||||||
|
sizeof(task_title));
|
||||||
|
task_set_title(task, strdup(task_title));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If install is inactive, end task (regardless
|
||||||
|
* of status) */
|
||||||
|
if (!install_active)
|
||||||
|
pfd_install_handle->status = PLAY_FEATURE_DELIVERY_INSTALL_END;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case PLAY_FEATURE_DELIVERY_INSTALL_END:
|
||||||
|
{
|
||||||
|
const char *msg_str = msg_hash_to_str(MSG_CORE_INSTALL_FAILED);
|
||||||
|
char task_title[PATH_MAX_LENGTH];
|
||||||
|
|
||||||
|
task_title[0] = '\0';
|
||||||
|
|
||||||
|
/* Set final task title */
|
||||||
|
task_free_title(task);
|
||||||
|
|
||||||
|
if (pfd_install_handle->success)
|
||||||
|
msg_str = pfd_install_handle->core_already_installed ?
|
||||||
|
msg_hash_to_str(MSG_LATEST_CORE_INSTALLED) :
|
||||||
|
msg_hash_to_str(MSG_CORE_INSTALLED);
|
||||||
|
|
||||||
|
strlcpy(task_title, msg_str, sizeof(task_title));
|
||||||
|
strlcat(task_title, pfd_install_handle->display_name,
|
||||||
|
sizeof(task_title));
|
||||||
|
|
||||||
|
task_set_title(task, strdup(task_title));
|
||||||
|
}
|
||||||
|
/* fall-through */
|
||||||
|
default:
|
||||||
|
task_set_progress(task, 100);
|
||||||
|
goto task_finished;
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
task_finished:
|
||||||
|
|
||||||
|
if (task)
|
||||||
|
task_set_finished(task, true);
|
||||||
|
|
||||||
|
free_play_feature_delivery_install_handle(pfd_install_handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool task_play_feature_delivery_core_install_finder(
|
||||||
|
retro_task_t *task, void *user_data)
|
||||||
|
{
|
||||||
|
if (!task)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (task->handler == task_play_feature_delivery_core_install_handler)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void task_push_play_feature_delivery_core_install(
|
||||||
|
core_updater_list_t* core_list,
|
||||||
|
const char *filename)
|
||||||
|
{
|
||||||
|
task_finder_data_t find_data;
|
||||||
|
char task_title[PATH_MAX_LENGTH];
|
||||||
|
const core_updater_list_entry_t *list_entry = NULL;
|
||||||
|
retro_task_t *task = NULL;
|
||||||
|
play_feature_delivery_install_handle_t *pfd_install_handle = (play_feature_delivery_install_handle_t*)
|
||||||
|
calloc(1, sizeof(play_feature_delivery_install_handle_t));
|
||||||
|
|
||||||
|
task_title[0] = '\0';
|
||||||
|
|
||||||
|
/* Sanity check */
|
||||||
|
if (!core_list ||
|
||||||
|
string_is_empty(filename) ||
|
||||||
|
!pfd_install_handle ||
|
||||||
|
!play_feature_delivery_enabled())
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
/* Get core updater list entry */
|
||||||
|
if (!core_updater_list_get_filename(
|
||||||
|
core_list, filename, &list_entry))
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
if (string_is_empty(list_entry->local_core_path) ||
|
||||||
|
string_is_empty(list_entry->display_name))
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
/* Only one core may be downloaded at a time */
|
||||||
|
find_data.func = task_play_feature_delivery_core_install_finder;
|
||||||
|
find_data.userdata = NULL;
|
||||||
|
|
||||||
|
if (task_queue_find(&find_data))
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
/* Configure handle */
|
||||||
|
pfd_install_handle->core_filename = strdup(list_entry->remote_filename);
|
||||||
|
pfd_install_handle->local_core_path = strdup(list_entry->local_core_path);
|
||||||
|
pfd_install_handle->display_name = strdup(list_entry->display_name);
|
||||||
|
pfd_install_handle->success = false;
|
||||||
|
pfd_install_handle->core_already_installed = false;
|
||||||
|
pfd_install_handle->status = PLAY_FEATURE_DELIVERY_INSTALL_BEGIN;
|
||||||
|
|
||||||
|
/* Create task */
|
||||||
|
task = task_init();
|
||||||
|
|
||||||
|
if (!task)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
/* Configure task */
|
||||||
|
strlcpy(task_title, msg_hash_to_str(MSG_UPDATING_CORE),
|
||||||
|
sizeof(task_title));
|
||||||
|
strlcat(task_title, pfd_install_handle->display_name,
|
||||||
|
sizeof(task_title));
|
||||||
|
|
||||||
|
task->handler = task_play_feature_delivery_core_install_handler;
|
||||||
|
task->state = pfd_install_handle;
|
||||||
|
task->mute = false;
|
||||||
|
task->title = strdup(task_title);
|
||||||
|
task->alternative_look = true;
|
||||||
|
task->progress = 0;
|
||||||
|
task->callback = cb_task_core_updater_download;
|
||||||
|
|
||||||
|
/* Install process may involve the *deletion*
|
||||||
|
* of an existing core file. If core is
|
||||||
|
* already running, must therefore unload it
|
||||||
|
* to prevent undefined behaviour */
|
||||||
|
if (rarch_ctl(RARCH_CTL_IS_CORE_LOADED, (void*)list_entry->local_core_path))
|
||||||
|
command_event(CMD_EVENT_UNLOAD_CORE, NULL);
|
||||||
|
|
||||||
|
/* Push task */
|
||||||
|
task_queue_push(task);
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
error:
|
||||||
|
|
||||||
|
/* Clean up task */
|
||||||
|
if (task)
|
||||||
|
{
|
||||||
|
free(task);
|
||||||
|
task = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Clean up handle */
|
||||||
|
free_play_feature_delivery_install_handle(pfd_install_handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
@ -96,6 +96,11 @@ void task_push_update_installed_cores(
|
|||||||
bool auto_backup, size_t auto_backup_history_size,
|
bool auto_backup, size_t auto_backup_history_size,
|
||||||
const char *path_dir_libretro,
|
const char *path_dir_libretro,
|
||||||
const char *path_dir_core_assets);
|
const char *path_dir_core_assets);
|
||||||
|
#if defined(ANDROID)
|
||||||
|
void task_push_play_feature_delivery_core_install(
|
||||||
|
core_updater_list_t* core_list,
|
||||||
|
const char *filename);
|
||||||
|
#endif
|
||||||
|
|
||||||
bool task_push_pl_entry_thumbnail_download(
|
bool task_push_pl_entry_thumbnail_download(
|
||||||
const char *system,
|
const char *system,
|
||||||
|
Loading…
Reference in New Issue
Block a user