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)))
|
||||
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 ###
|
||||
###############WIP################
|
||||
|
18
core_info.c
18
core_info.c
@ -36,6 +36,10 @@
|
||||
#include "uwp/uwp_func.h"
|
||||
#endif
|
||||
|
||||
#if defined(ANDROID)
|
||||
#include "play_feature_delivery/play_feature_delivery.h"
|
||||
#endif
|
||||
|
||||
enum compare_op
|
||||
{
|
||||
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';
|
||||
|
||||
#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))
|
||||
return false;
|
||||
|
||||
@ -1599,6 +1610,13 @@ bool core_info_get_core_lock(const char *core_path, bool validate_path)
|
||||
|
||||
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))
|
||||
return false;
|
||||
|
||||
|
@ -36,6 +36,7 @@
|
||||
struct core_updater_list
|
||||
{
|
||||
core_updater_list_entry_t *entries;
|
||||
enum core_updater_list_type type;
|
||||
};
|
||||
|
||||
/* Cached ('global') core updater list */
|
||||
@ -109,6 +110,7 @@ core_updater_list_t *core_updater_list_init(void)
|
||||
|
||||
/* Initialise members */
|
||||
core_list->entries = NULL;
|
||||
core_list->type = CORE_UPDATER_LIST_TYPE_UNKNOWN;
|
||||
|
||||
return core_list;
|
||||
}
|
||||
@ -129,6 +131,8 @@ void core_updater_list_reset(core_updater_list_t *core_list)
|
||||
|
||||
RBUF_FREE(core_list->entries);
|
||||
}
|
||||
|
||||
core_list->type = CORE_UPDATER_LIST_TYPE_UNKNOWN;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
/* 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
|
||||
* to the specified entry index.
|
||||
* 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_libretro_info,
|
||||
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 *tmp_url = NULL;
|
||||
@ -384,11 +400,14 @@ static bool core_updater_list_set_paths(
|
||||
local_core_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;
|
||||
|
||||
if (string_is_empty(path_dir_libretro) ||
|
||||
string_is_empty(path_libretro_info) ||
|
||||
/* Only buildbot cores require the buildbot URL */
|
||||
if ((list_type == CORE_UPDATER_LIST_TYPE_BUILDBOT) &&
|
||||
string_is_empty(network_buildbot_url))
|
||||
return false;
|
||||
|
||||
@ -404,7 +423,10 @@ static bool core_updater_list_set_paths(
|
||||
|
||||
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(
|
||||
remote_core_path,
|
||||
network_buildbot_url,
|
||||
@ -418,6 +440,7 @@ static bool core_updater_list_set_paths(
|
||||
remote_core_path, tmp_url, sizeof(remote_core_path));
|
||||
if (tmp_url)
|
||||
free(tmp_url);
|
||||
}
|
||||
|
||||
if (entry->remote_core_path)
|
||||
{
|
||||
@ -677,7 +700,8 @@ static void core_updater_list_add_entry(
|
||||
path_dir_libretro,
|
||||
path_libretro_info,
|
||||
network_buildbot_url,
|
||||
filename_str))
|
||||
filename_str,
|
||||
CORE_UPDATER_LIST_TYPE_BUILDBOT))
|
||||
goto error;
|
||||
|
||||
if (!core_updater_list_set_core_info(
|
||||
@ -825,6 +849,9 @@ bool core_updater_list_parse_network_data(
|
||||
/* Sort completed list */
|
||||
core_updater_list_qsort(core_list);
|
||||
|
||||
/* Set list type */
|
||||
core_list->type = CORE_UPDATER_LIST_TYPE_BUILDBOT;
|
||||
|
||||
return true;
|
||||
|
||||
error:
|
||||
@ -835,3 +862,114 @@ error:
|
||||
|
||||
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
|
||||
|
||||
/* 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
|
||||
* on the buildbot */
|
||||
typedef struct
|
||||
@ -99,6 +111,11 @@ void core_updater_list_free_cached(void);
|
||||
/* Returns number of entries in core updater 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
|
||||
* to the specified entry index.
|
||||
* Returns false if index is invalid. */
|
||||
@ -138,6 +155,16 @@ bool core_updater_list_parse_network_data(
|
||||
const char *network_buildbot_url,
|
||||
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
|
||||
|
||||
#endif
|
||||
|
@ -1938,6 +1938,16 @@ static void frontend_unix_init(void *data)
|
||||
"doVibrate", "(IIII)V");
|
||||
GET_METHOD_ID(env, android_app->getUserLanguageString, class,
|
||||
"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,
|
||||
android_app->getIntent);
|
||||
|
||||
|
@ -166,6 +166,12 @@ struct android_app
|
||||
jmethodID getUserLanguageString;
|
||||
jmethodID doVibrate;
|
||||
|
||||
jmethodID isPlayStoreBuild;
|
||||
jmethodID getAvailableCores;
|
||||
jmethodID getInstalledCores;
|
||||
jmethodID downloadCore;
|
||||
jmethodID deleteCore;
|
||||
|
||||
struct
|
||||
{
|
||||
unsigned width, height;
|
||||
|
@ -1671,3 +1671,10 @@ MISC FILE FORMATS
|
||||
TIME
|
||||
============================================================ */
|
||||
#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,
|
||||
"Core installed: "
|
||||
)
|
||||
MSG_HASH(
|
||||
MSG_CORE_INSTALL_FAILED,
|
||||
"Failed to install core: "
|
||||
)
|
||||
MSG_HASH(
|
||||
MSG_SCANNING_CORES,
|
||||
"Scanning cores..."
|
||||
|
@ -89,6 +89,10 @@
|
||||
#include "../../uwp/uwp_func.h"
|
||||
#endif
|
||||
|
||||
#if defined(ANDROID)
|
||||
#include "../../play_feature_delivery/play_feature_delivery.h"
|
||||
#endif
|
||||
|
||||
enum
|
||||
{
|
||||
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)
|
||||
{
|
||||
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
|
||||
* it if required */
|
||||
@ -4036,12 +4042,49 @@ static int action_ok_core_updater_list(const char *path,
|
||||
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... */
|
||||
menu_entries_ctl(MENU_ENTRIES_CTL_SET_REFRESH, &refresh);
|
||||
generic_action_ok_command(CMD_EVENT_NETWORK_INIT);
|
||||
|
||||
/* Push core list update task */
|
||||
task_push_get_core_updater_list(core_list, false, true);
|
||||
}
|
||||
|
||||
return generic_action_ok_displaylist_push(
|
||||
path, NULL, label, type, idx, entry_idx,
|
||||
@ -4466,6 +4509,14 @@ static int action_ok_core_updater_download(const char *path,
|
||||
if (!core_list)
|
||||
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(
|
||||
core_list, path, 0, false,
|
||||
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);
|
||||
|
||||
/* 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);
|
||||
|
||||
/* Reload core info files */
|
||||
|
@ -62,6 +62,10 @@
|
||||
#include "../frontend/drivers/platform_unix.h"
|
||||
#endif
|
||||
|
||||
#if defined(ANDROID)
|
||||
#include "../play_feature_delivery/play_feature_delivery.h"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_CDROM
|
||||
#include <vfs/vfs_implementation_cdrom.h>
|
||||
#include <media/media_detect_cd.h>
|
||||
@ -670,6 +674,12 @@ end:
|
||||
/* Check whether core is currently locked */
|
||||
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
|
||||
* > Note: Have to set core_path as both the
|
||||
* 'path' and 'label' parameters (otherwise
|
||||
@ -686,6 +696,7 @@ end:
|
||||
info->list, count, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CORE_LOCK));
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Backup core */
|
||||
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))
|
||||
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,
|
||||
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_UPDATE_INSTALLED_CORES),
|
||||
msg_hash_to_str(MENU_ENUM_LABEL_UPDATE_INSTALLED_CORES),
|
||||
|
@ -118,6 +118,10 @@
|
||||
#include <3ds/services/cfgu.h>
|
||||
#endif
|
||||
|
||||
#if defined(ANDROID)
|
||||
#include "../play_feature_delivery/play_feature_delivery.h"
|
||||
#endif
|
||||
|
||||
#define _3_SECONDS 3000000
|
||||
#define _6_SECONDS 6000000
|
||||
#define _9_SECONDS 9000000
|
||||
@ -16682,6 +16686,13 @@ static bool setting_append_list(
|
||||
parent_group = msg_hash_to_str(MENU_ENUM_LABEL_UPDATER_SETTINGS);
|
||||
START_SUB_GROUP(list, list_info, "State", &group_info, &subgroup_info, parent_group);
|
||||
#ifdef HAVE_NETWORKING
|
||||
|
||||
#if defined(ANDROID)
|
||||
/* Play Store builds do not fetch cores
|
||||
* from the buildbot */
|
||||
if (!play_feature_delivery_enabled())
|
||||
#endif
|
||||
{
|
||||
CONFIG_STRING(
|
||||
list, list_info,
|
||||
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);
|
||||
(*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;
|
||||
}
|
||||
|
||||
CONFIG_STRING(
|
||||
list, list_info,
|
||||
@ -16746,6 +16758,12 @@ static bool setting_append_list(
|
||||
SD_FLAG_NONE
|
||||
);
|
||||
|
||||
#if defined(ANDROID)
|
||||
/* Play Store builds do not support automatic
|
||||
* core backups */
|
||||
if (!play_feature_delivery_enabled())
|
||||
#endif
|
||||
{
|
||||
CONFIG_BOOL(
|
||||
list, list_info,
|
||||
&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].offset_by = 1;
|
||||
menu_settings_list_current_add_range(list, list_info, (*list)[list_info->index - 1].offset_by, 500, 1, true, true);
|
||||
}
|
||||
#endif
|
||||
END_SUB_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_EXTRACTING_CORE,
|
||||
MSG_CORE_INSTALLED,
|
||||
MSG_CORE_INSTALL_FAILED,
|
||||
MSG_SCANNING_CORES,
|
||||
MSG_CHECKING_CORE,
|
||||
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"
|
||||
#endif
|
||||
|
||||
#if defined(ANDROID)
|
||||
#include "play_feature_delivery/play_feature_delivery.h"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_DISCORD
|
||||
#include <discord_rpc.h>
|
||||
#include "deps/discord-rpc/include/discord_rpc.h"
|
||||
@ -17539,6 +17543,10 @@ void main_exit(void *args)
|
||||
|
||||
rtime_deinit();
|
||||
|
||||
#if defined(ANDROID)
|
||||
play_feature_delivery_deinit();
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32) && !defined(_XBOX) && !defined(__WINRT__)
|
||||
CoUninitialize();
|
||||
#endif
|
||||
@ -17577,6 +17585,10 @@ int rarch_main(int argc, char *argv[], void *data)
|
||||
|
||||
rtime_init();
|
||||
|
||||
#if defined(ANDROID)
|
||||
play_feature_delivery_init();
|
||||
#endif
|
||||
|
||||
libretro_free_system_info(&p_rarch->runloop_system.info);
|
||||
command_event(CMD_EVENT_HISTORY_DEINIT, NULL);
|
||||
rarch_favorites_deinit();
|
||||
|
@ -36,6 +36,10 @@
|
||||
#include "../core_info.h"
|
||||
#include "../core_backup.h"
|
||||
|
||||
#if defined(ANDROID)
|
||||
#include "../play_feature_delivery/play_feature_delivery.h"
|
||||
#endif
|
||||
|
||||
#define CORE_BACKUP_CHUNK_SIZE 4096
|
||||
|
||||
enum core_backup_status
|
||||
@ -778,6 +782,27 @@ static void task_core_restore_handler(retro_task_t *task)
|
||||
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 */
|
||||
backup_handle->core_file = intfstream_open_file(
|
||||
backup_handle->core_path, RETRO_VFS_FILE_ACCESS_WRITE,
|
||||
|
@ -38,6 +38,10 @@
|
||||
#include "../verbosity.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)
|
||||
#include "../menu/menu_entries.h"
|
||||
#endif
|
||||
@ -50,29 +54,6 @@ enum core_updater_list_status
|
||||
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
|
||||
{
|
||||
core_updater_list_t* core_list;
|
||||
@ -85,6 +66,18 @@ typedef struct core_updater_list_handle
|
||||
bool http_task_success;
|
||||
} 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
|
||||
{
|
||||
char *path_dir_libretro;
|
||||
@ -110,6 +103,17 @@ typedef struct core_updater_download_handle
|
||||
bool backup_enabled;
|
||||
} 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
|
||||
{
|
||||
char *path_dir_libretro;
|
||||
@ -127,6 +131,26 @@ typedef struct update_installed_cores_handle
|
||||
bool auto_backup;
|
||||
} 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 */
|
||||
/*********************/
|
||||
@ -393,6 +417,13 @@ void *task_push_get_core_updater_list(
|
||||
core_updater_list_handle_t *list_handle = (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 */
|
||||
if (!core_list || !list_handle)
|
||||
goto error;
|
||||
@ -952,6 +983,13 @@ void *task_push_core_updater_download(
|
||||
task_title[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 */
|
||||
if (!core_list ||
|
||||
string_is_empty(filename) ||
|
||||
@ -1410,6 +1448,13 @@ void task_push_update_installed_cores(
|
||||
(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 */
|
||||
if (!update_installed_handle ||
|
||||
string_is_empty(path_dir_libretro))
|
||||
@ -1471,3 +1516,265 @@ error:
|
||||
/* Clean up 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,
|
||||
const char *path_dir_libretro,
|
||||
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(
|
||||
const char *system,
|
||||
|
Loading…
Reference in New Issue
Block a user