From ddc9f583cc6a4fe5fc5ff46634e8ac7c10ab66a5 Mon Sep 17 00:00:00 2001 From: npes87184 Date: Sun, 12 Aug 2018 10:40:00 +0800 Subject: [PATCH] Support drag & drop a file to transfer it to device Signed-off-by: npes87184 --- app/src/device.h | 1 + app/src/file_handler.c | 98 +++++++++++++++++++++++++++--------------- app/src/file_handler.h | 21 ++++++--- app/src/scrcpy.c | 11 ++++- 4 files changed, 90 insertions(+), 41 deletions(-) diff --git a/app/src/device.h b/app/src/device.h index d01d6ed294..125dda3a91 100644 --- a/app/src/device.h +++ b/app/src/device.h @@ -7,6 +7,7 @@ #include "net.h" #define DEVICE_NAME_FIELD_LENGTH 64 +#define DEVICE_SDCARD_PATH "/sdcard/" // name must be at least DEVICE_NAME_FIELD_LENGTH bytes SDL_bool device_read_info(socket_t device_socket, char *name, struct size *frame_size); diff --git a/app/src/file_handler.c b/app/src/file_handler.c index 449946fb10..4dc23ce355 100644 --- a/app/src/file_handler.c +++ b/app/src/file_handler.c @@ -2,57 +2,62 @@ #include #include "command.h" +#include "device.h" #include "lockutil.h" #include "log.h" -// NOTE(adopi) this can be more generic: -// it could be used with a command queue instead of a filename queue -// then we would have a generic invoker (useful if we want to handle more async commands) +void request_free(struct request *req) { + if (!req) { + return; + } + SDL_free(req->file); + free(req); +} -SDL_bool file_queue_is_empty(const struct file_queue *queue) { +SDL_bool request_queue_is_empty(const struct request_queue *queue) { return queue->head == queue->tail; } -SDL_bool file_queue_is_full(const struct file_queue *queue) { - return (queue->head + 1) % FILE_QUEUE_SIZE == queue->tail; +SDL_bool request_queue_is_full(const struct request_queue *queue) { + return (queue->head + 1) % REQUEST_QUEUE_SIZE == queue->tail; } -SDL_bool file_queue_init(struct file_queue *queue) { +SDL_bool request_queue_init(struct request_queue *queue) { queue->head = 0; queue->tail = 0; return SDL_TRUE; } -void file_queue_destroy(struct file_queue *queue) { +void request_queue_destroy(struct request_queue *queue) { int i = queue->tail; while (i != queue->head) { - SDL_free(queue->data[i]); - i = (i + 1) % FILE_QUEUE_SIZE; + request_free(queue->reqs[i]); + i = (i + 1) % REQUEST_QUEUE_SIZE; } } -SDL_bool file_queue_push(struct file_queue *queue, const char *file) { - if (file_queue_is_full(queue)) { +SDL_bool request_queue_push(struct request_queue *queue, struct request *req) { + if (request_queue_is_full(queue)) { return SDL_FALSE; } - queue->data[queue->head] = SDL_strdup(file); - queue->head = (queue->head + 1) % FILE_QUEUE_SIZE; + queue->reqs[queue->head] = req; + queue->head = (queue->head + 1) % REQUEST_QUEUE_SIZE; return SDL_TRUE; } -SDL_bool file_queue_take(struct file_queue *queue, char **file) { - if (file_queue_is_empty(queue)) { +SDL_bool request_queue_take(struct request_queue *queue, struct request **req) { + if (request_queue_is_empty(queue)) { return SDL_FALSE; } // transfer ownership - *file = queue->data[queue->tail]; - queue->tail = (queue->tail + 1) % FILE_QUEUE_SIZE; + *req = queue->reqs[queue->tail]; + queue->tail = (queue->tail + 1) % REQUEST_QUEUE_SIZE; return SDL_TRUE; } SDL_bool file_handler_init(struct file_handler *file_handler, const char *serial) { - if (!file_queue_init(&file_handler->queue)) { + if (!request_queue_init(&file_handler->queue)) { return SDL_FALSE; } @@ -88,12 +93,21 @@ SDL_bool file_handler_init(struct file_handler *file_handler, const char *serial void file_handler_destroy(struct file_handler *file_handler) { SDL_DestroyCond(file_handler->event_cond); SDL_DestroyMutex(file_handler->mutex); - file_queue_destroy(&file_handler->queue); + request_queue_destroy(&file_handler->queue); SDL_free((void *) file_handler->serial); } -SDL_bool file_handler_do(struct file_handler *file_handler, const char *file) { +static process_t install_apk(const char *serial, const char *file) { + return adb_install(serial, file); +} + +static process_t push_file(const char *serial, const char *file) { + return adb_push(serial, file, DEVICE_SDCARD_PATH); +} + +SDL_bool file_handler_add_request(struct file_handler *file_handler, const char *file, req_action_t action) { SDL_bool res; + struct request *req = (struct request *) malloc(sizeof(struct request)); // start file_handler if it's used for the first time if (!file_handler->initialized) { @@ -103,9 +117,18 @@ SDL_bool file_handler_do(struct file_handler *file_handler, const char *file) { file_handler->initialized = SDL_TRUE; } + LOGI("Adding request %s", file); + req->file = SDL_strdup(file); + req->action = action; + if (action == INSTALL_APK) { + req->func = install_apk; + } else { + req->func = push_file; + } + mutex_lock(file_handler->mutex); - SDL_bool was_empty = file_queue_is_empty(&file_handler->queue); - res = file_queue_push(&file_handler->queue, file); + SDL_bool was_empty = request_queue_is_empty(&file_handler->queue); + res = request_queue_push(&file_handler->queue, req); if (was_empty) { cond_signal(file_handler->event_cond); } @@ -118,7 +141,7 @@ static int run_file_handler(void *data) { for (;;) { mutex_lock(file_handler->mutex); - while (!file_handler->stopped && file_queue_is_empty(&file_handler->queue)) { + while (!file_handler->stopped && request_queue_is_empty(&file_handler->queue)) { cond_wait(file_handler->event_cond, file_handler->mutex); } if (file_handler->stopped) { @@ -126,25 +149,32 @@ static int run_file_handler(void *data) { mutex_unlock(file_handler->mutex); break; } - char *current_apk; + struct request *req; + process_t process; + const char *cmd; #ifdef BUILD_DEBUG - bool non_empty = file_queue_take(&file_handler->queue, ¤t_apk); + bool non_empty = request_queue_take(&file_handler->queue, &req); SDL_assert(non_empty); #else - file_queue_take(&file_handler->queue, ¤t_apk); + request_queue_take(&file_handler->queue, &req); #endif - LOGI("Installing %s...", current_apk); - process_t process = adb_install(file_handler->serial, current_apk); + LOGI("Processing %s...", req->file); + process = req->func(file_handler->serial, req->file); file_handler->current_process = process; - mutex_unlock(file_handler->mutex); - if (process_check_success(process, "adb install")) { - LOGI("%s installed successfully", current_apk); + if (req->action == INSTALL_APK) { + cmd = "adb install"; + } else { + cmd = "adb push"; + } + + if (process_check_success(process, cmd)) { + LOGI("Process %s successfully", req->file); } else { - LOGE("Failed to install %s", current_apk); + LOGE("Failed to process %s", req->file); } - SDL_free(current_apk); + request_free(req); } return 0; } diff --git a/app/src/file_handler.h b/app/src/file_handler.h index 9cee9d3e4b..39dbf02a97 100644 --- a/app/src/file_handler.h +++ b/app/src/file_handler.h @@ -6,12 +6,21 @@ #include #include "command.h" -#define FILE_QUEUE_SIZE 16 +#define REQUEST_QUEUE_SIZE 16 -// NOTE(AdoPi) file_queue and control_event can use a generic queue +typedef enum { + INSTALL_APK = 0, + PUSH_FILE, +} req_action_t; -struct file_queue { - char *data[FILE_QUEUE_SIZE]; +struct request { + process_t (*func)(const char *, const char *); + char *file; + req_action_t action; +}; + +struct request_queue { + struct request *reqs[REQUEST_QUEUE_SIZE]; int tail; int head; }; @@ -24,7 +33,7 @@ struct file_handler { SDL_bool stopped; SDL_bool initialized; process_t current_process; - struct file_queue queue; + struct request_queue queue; }; SDL_bool file_handler_init(struct file_handler *file_handler, const char *serial); @@ -34,6 +43,6 @@ SDL_bool file_handler_start(struct file_handler *file_handler); void file_handler_stop(struct file_handler *file_handler); void file_handler_join(struct file_handler *file_handler); -SDL_bool file_handler_do(struct file_handler *file_handler, const char *filename); +SDL_bool file_handler_add_request(struct file_handler *file_handler, const char *filename, req_action_t action); #endif diff --git a/app/src/scrcpy.c b/app/src/scrcpy.c index 7293316cc2..fc5377f5ca 100644 --- a/app/src/scrcpy.c +++ b/app/src/scrcpy.c @@ -56,6 +56,11 @@ static int event_watcher(void *data, SDL_Event *event) { } #endif +static int is_apk(const char *file) { + const char *ext = strrchr(file, '.'); + return ext && !strcmp(ext, ".apk"); +} + static void event_loop(void) { #ifdef CONTINUOUS_RESIZING_WORKAROUND SDL_AddEventWatch(event_watcher, NULL); @@ -105,7 +110,11 @@ static void event_loop(void) { input_manager_process_mouse_button(&input_manager, &event.button); break; case SDL_DROPFILE: - file_handler_do(&file_handler, event.drop.file); + if (is_apk(event.drop.file)) { + file_handler_add_request(&file_handler, event.drop.file, INSTALL_APK); + } else { + file_handler_add_request(&file_handler, event.drop.file, PUSH_FILE); + } break; } }