Compare commits

..

1 Commits

Author SHA1 Message Date
Romain Vimont
9b6e511322 Push to /sdcard/Download/ by default
Change the default push target from /sdcard/ to /sdcard/Download/.

Pushing to the root of /sdcard/ is not very convenient, many apps do not
expose its content directly.

It can still be changed by --push-target.
2021-06-13 22:47:16 +02:00
23 changed files with 91 additions and 367 deletions

View File

@@ -303,8 +303,7 @@ To start scrcpy using a v4l2 sink:
```bash
scrcpy --v4l2-sink=/dev/videoN
scrcpy --v4l2-sink=/dev/videoN --no-display # disable mirroring window
scrcpy --v4l2-sink=/dev/videoN -N # short version
scrcpy --v4l2-sink=/dev/videoN -N # --no-display to disable mirroring window
```
(replace `N` by the device ID, check with `ls /dev/video*`)

View File

@@ -20,7 +20,6 @@ src = [
'src/stream.c',
'src/tiny_xpm.c',
'src/video_buffer.c',
'src/util/log.c',
'src/util/net.c',
'src/util/process.c',
'src/util/str_util.c',

View File

@@ -193,7 +193,7 @@ It requires to lock the video orientation (see --lock-video-orientation).
.TP
.BI "\-V, \-\-verbosity " value
Set the log level ("verbose", "debug", "info", "warn" or "error").
Set the log level ("debug", "info", "warn" or "error").
Default is "info" for release builds, "debug" for debug builds.

View File

@@ -184,7 +184,7 @@ scrcpy_print_usage(const char *arg0) {
"\n"
#endif
" -V, --verbosity value\n"
" Set the log level (verbose, debug, info, warn or error).\n"
" Set the log level (debug, info, warn or error).\n"
#ifndef NDEBUG
" Default is debug.\n"
#else
@@ -505,11 +505,6 @@ parse_display_id(const char *s, uint32_t *display_id) {
static bool
parse_log_level(const char *s, enum sc_log_level *log_level) {
if (!strcmp(s, "verbose")) {
*log_level = SC_LOG_LEVEL_VERBOSE;
return true;
}
if (!strcmp(s, "debug")) {
*log_level = SC_LOG_LEVEL_DEBUG;
return true;

View File

@@ -1,7 +1,6 @@
#include "control_msg.h"
#include <assert.h>
#include <inttypes.h>
#include <stdlib.h>
#include <string.h>
@@ -9,52 +8,6 @@
#include "util/log.h"
#include "util/str_util.h"
/**
* Map an enum value to a string based on an array, without crashing on an
* out-of-bounds index.
*/
#define ENUM_TO_LABEL(labels, value) \
((size_t) (value) < ARRAY_LEN(labels) ? labels[value] : "???")
#define KEYEVENT_ACTION_LABEL(value) \
ENUM_TO_LABEL(android_keyevent_action_labels, value)
#define MOTIONEVENT_ACTION_LABEL(value) \
ENUM_TO_LABEL(android_motionevent_action_labels, value)
#define SCREEN_POWER_MODE_LABEL(value) \
ENUM_TO_LABEL(screen_power_mode_labels, value)
static const char *const android_keyevent_action_labels[] = {
"down",
"up",
"multi",
};
static const char *const android_motionevent_action_labels[] = {
"down",
"up",
"move",
"cancel",
"outside",
"ponter-down",
"pointer-up",
"hover-move",
"scroll",
"hover-enter"
"hover-exit",
"btn-press",
"btn-release",
};
static const char *const screen_power_mode_labels[] = {
"off",
"doze",
"normal",
"doze-suspend",
"suspend",
};
static void
write_position(uint8_t *buf, const struct position *position) {
buffer_write32be(&buf[0], position->point.x);
@@ -140,94 +93,6 @@ control_msg_serialize(const struct control_msg *msg, unsigned char *buf) {
}
}
void
control_msg_log(const struct control_msg *msg) {
#define LOG_CMSG(fmt, ...) LOGV("input: " fmt, ## __VA_ARGS__)
switch (msg->type) {
case CONTROL_MSG_TYPE_INJECT_KEYCODE:
LOG_CMSG("key %-4s code=%d repeat=%" PRIu32 " meta=%06lx",
KEYEVENT_ACTION_LABEL(msg->inject_keycode.action),
(int) msg->inject_keycode.keycode,
msg->inject_keycode.repeat,
(long) msg->inject_keycode.metastate);
break;
case CONTROL_MSG_TYPE_INJECT_TEXT:
LOG_CMSG("text \"%s\"", msg->inject_text.text);
break;
case CONTROL_MSG_TYPE_INJECT_TOUCH_EVENT: {
int action = msg->inject_touch_event.action
& AMOTION_EVENT_ACTION_MASK;
uint64_t id = msg->inject_touch_event.pointer_id;
if (id == POINTER_ID_MOUSE || id == POINTER_ID_VIRTUAL_FINGER) {
// string pointer id
LOG_CMSG("touch [id=%s] %-4s position=%" PRIi32 ",%" PRIi32
" pressure=%g buttons=%06lx",
id == POINTER_ID_MOUSE ? "mouse" : "vfinger",
MOTIONEVENT_ACTION_LABEL(action),
msg->inject_touch_event.position.point.x,
msg->inject_touch_event.position.point.y,
msg->inject_touch_event.pressure,
(long) msg->inject_touch_event.buttons);
} else {
// numeric pointer id
#ifndef __WIN32
# define PRIu64_ PRIu64
#else
# define PRIu64_ "I64u" // Windows...
#endif
LOG_CMSG("touch [id=%" PRIu64_ "] %-4s position=%" PRIi32 ",%"
PRIi32 " pressure=%g buttons=%06lx",
id,
MOTIONEVENT_ACTION_LABEL(action),
msg->inject_touch_event.position.point.x,
msg->inject_touch_event.position.point.y,
msg->inject_touch_event.pressure,
(long) msg->inject_touch_event.buttons);
}
break;
}
case CONTROL_MSG_TYPE_INJECT_SCROLL_EVENT:
LOG_CMSG("scroll position=%" PRIi32 ",%" PRIi32 " hscroll=%" PRIi32
" vscroll=%" PRIi32,
msg->inject_scroll_event.position.point.x,
msg->inject_scroll_event.position.point.y,
msg->inject_scroll_event.hscroll,
msg->inject_scroll_event.vscroll);
break;
case CONTROL_MSG_TYPE_BACK_OR_SCREEN_ON:
LOG_CMSG("back-or-screen-on %s",
KEYEVENT_ACTION_LABEL(msg->inject_keycode.action));
break;
case CONTROL_MSG_TYPE_SET_CLIPBOARD:
LOG_CMSG("clipboard %s \"%s\"",
msg->set_clipboard.paste ? "paste" : "copy",
msg->set_clipboard.text);
break;
case CONTROL_MSG_TYPE_SET_SCREEN_POWER_MODE:
LOG_CMSG("power mode %s",
SCREEN_POWER_MODE_LABEL(msg->set_screen_power_mode.mode));
break;
case CONTROL_MSG_TYPE_EXPAND_NOTIFICATION_PANEL:
LOG_CMSG("expand notification panel");
break;
case CONTROL_MSG_TYPE_EXPAND_SETTINGS_PANEL:
LOG_CMSG("expand settings panel");
break;
case CONTROL_MSG_TYPE_COLLAPSE_PANELS:
LOG_CMSG("collapse panels");
break;
case CONTROL_MSG_TYPE_GET_CLIPBOARD:
LOG_CMSG("get clipboard");
break;
case CONTROL_MSG_TYPE_ROTATE_DEVICE:
LOG_CMSG("rotate device");
break;
default:
LOG_CMSG("unknown type: %u", (unsigned) msg->type);
break;
}
}
void
control_msg_destroy(struct control_msg *msg) {
switch (msg->type) {

View File

@@ -17,8 +17,8 @@
// type: 1 byte; paste flag: 1 byte; length: 4 bytes
#define CONTROL_MSG_CLIPBOARD_TEXT_MAX_LENGTH (CONTROL_MSG_MAX_SIZE - 6)
#define POINTER_ID_MOUSE UINT64_C(-1)
#define POINTER_ID_VIRTUAL_FINGER UINT64_C(-2)
#define POINTER_ID_MOUSE UINT64_C(-1);
#define POINTER_ID_VIRTUAL_FINGER UINT64_C(-2);
enum control_msg_type {
CONTROL_MSG_TYPE_INJECT_KEYCODE,
@@ -84,9 +84,6 @@ struct control_msg {
size_t
control_msg_serialize(const struct control_msg *msg, unsigned char *buf);
void
control_msg_log(const struct control_msg *msg);
void
control_msg_destroy(struct control_msg *msg);

View File

@@ -48,10 +48,6 @@ controller_destroy(struct controller *controller) {
bool
controller_push_msg(struct controller *controller,
const struct control_msg *msg) {
if (sc_get_log_level() <= SC_LOG_LEVEL_VERBOSE) {
control_msg_log(msg);
}
sc_mutex_lock(&controller->mutex);
bool was_empty = cbuf_is_empty(&controller->queue);
bool res = cbuf_push(&controller->queue, *msg);

View File

@@ -595,12 +595,8 @@ convert_mouse_motion(const SDL_MouseMotionEvent *from, struct screen *screen,
static void
input_manager_process_mouse_motion(struct input_manager *im,
const SDL_MouseMotionEvent *event) {
uint32_t mask = SDL_BUTTON_LMASK;
if (im->forward_all_clicks) {
mask |= SDL_BUTTON_MMASK | SDL_BUTTON_RMASK;
}
if (!(event->state & mask)) {
// do not send motion events when no click is pressed
if (!event->state) {
// do not send motion events when no button is pressed
return;
}
if (event->which == SDL_TOUCH_MOUSEID) {

View File

@@ -38,6 +38,24 @@ print_version(void) {
#endif
}
static SDL_LogPriority
convert_log_level_to_sdl(enum sc_log_level level) {
switch (level) {
case SC_LOG_LEVEL_DEBUG:
return SDL_LOG_PRIORITY_DEBUG;
case SC_LOG_LEVEL_INFO:
return SDL_LOG_PRIORITY_INFO;
case SC_LOG_LEVEL_WARN:
return SDL_LOG_PRIORITY_WARN;
case SC_LOG_LEVEL_ERROR:
return SDL_LOG_PRIORITY_ERROR;
default:
assert(!"unexpected log level");
return SDL_LOG_PRIORITY_INFO;
}
}
int
main(int argc, char *argv[]) {
#ifdef __WINDOWS__
@@ -61,7 +79,8 @@ main(int argc, char *argv[]) {
return 1;
}
sc_set_log_level(args.opts.log_level);
SDL_LogPriority sdl_log = convert_log_level_to_sdl(args.opts.log_level);
SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, sdl_log);
if (args.help) {
scrcpy_print_usage(argv[0]);

View File

@@ -35,14 +35,11 @@ record_packet_new(const AVPacket *packet) {
return NULL;
}
rec->packet = av_packet_alloc();
if (!rec->packet) {
free(rec);
return NULL;
}
// av_packet_ref() does not initialize all fields in old FFmpeg versions
// See <https://github.com/Genymobile/scrcpy/issues/707>
av_init_packet(&rec->packet);
if (av_packet_ref(rec->packet, packet)) {
av_packet_free(&rec->packet);
if (av_packet_ref(&rec->packet, packet)) {
free(rec);
return NULL;
}
@@ -51,8 +48,7 @@ record_packet_new(const AVPacket *packet) {
static void
record_packet_delete(struct record_packet *rec) {
av_packet_unref(rec->packet);
av_packet_free(&rec->packet);
av_packet_unref(&rec->packet);
free(rec);
}
@@ -148,8 +144,8 @@ run_recorder(void *data) {
struct record_packet *last = recorder->previous;
if (last) {
// assign an arbitrary duration to the last packet
last->packet->duration = 100000;
bool ok = recorder_write(recorder, last->packet);
last->packet.duration = 100000;
bool ok = recorder_write(recorder, &last->packet);
if (!ok) {
// failing to write the last frame is not very serious, no
// future frame may depend on it, so the resulting file
@@ -176,14 +172,13 @@ run_recorder(void *data) {
}
// config packets have no PTS, we must ignore them
if (rec->packet->pts != AV_NOPTS_VALUE
&& previous->packet->pts != AV_NOPTS_VALUE) {
if (rec->packet.pts != AV_NOPTS_VALUE
&& previous->packet.pts != AV_NOPTS_VALUE) {
// we now know the duration of the previous packet
previous->packet->duration =
rec->packet->pts - previous->packet->pts;
previous->packet.duration = rec->packet.pts - previous->packet.pts;
}
bool ok = recorder_write(recorder, previous->packet);
bool ok = recorder_write(recorder, &previous->packet);
record_packet_delete(previous);
if (!ok) {
LOGE("Could not record packet");

View File

@@ -13,7 +13,7 @@
#include "util/thread.h"
struct record_packet {
AVPacket *packet;
AVPacket packet;
struct record_packet *next;
};

View File

@@ -216,15 +216,14 @@ av_log_callback(void *avcl, int level, const char *fmt, va_list vl) {
if (priority == 0) {
return;
}
size_t fmt_len = strlen(fmt);
char *local_fmt = malloc(fmt_len + 10);
char *local_fmt = malloc(strlen(fmt) + 10);
if (!local_fmt) {
LOGC("Could not allocate string");
return;
}
memcpy(local_fmt, "[FFmpeg] ", 9); // do not write the final '\0'
memcpy(local_fmt + 9, fmt, fmt_len + 1); // include '\0'
// strcpy is safe here, the destination is large enough
strcpy(local_fmt, "[FFmpeg] ");
strcpy(local_fmt + 9, fmt);
SDL_LogMessageV(SDL_LOG_CATEGORY_VIDEO, priority, local_fmt, vl);
free(local_fmt);
}

View File

@@ -8,7 +8,6 @@
#include <stdint.h>
enum sc_log_level {
SC_LOG_LEVEL_VERBOSE,
SC_LOG_LEVEL_DEBUG,
SC_LOG_LEVEL_INFO,
SC_LOG_LEVEL_WARN,

View File

@@ -41,18 +41,6 @@ get_window_size(const struct screen *screen) {
return size;
}
static struct point
get_window_position(const struct screen *screen) {
int x;
int y;
SDL_GetWindowPosition(screen->window, &x, &y);
struct point point;
point.x = x;
point.y = y;
return point;
}
// set the window size to be applied when fullscreen is disabled
static void
set_window_size(struct screen *screen, struct size new_size) {
@@ -134,6 +122,13 @@ get_optimal_size(struct size current_size, struct size content_size) {
return window_size;
}
// same as get_optimal_size(), but read the current size from the window
static inline struct size
get_optimal_window_size(const struct screen *screen, struct size content_size) {
struct size window_size = get_window_size(screen);
return get_optimal_size(window_size, content_size);
}
// initially, there is no current size, so use the frame size as current size
// req_width and req_height, if not 0, are the sizes requested by the user
static inline struct size
@@ -667,20 +662,9 @@ screen_resize_to_fit(struct screen *screen) {
return;
}
struct point point = get_window_position(screen);
struct size window_size = get_window_size(screen);
struct size optimal_size =
get_optimal_size(window_size, screen->content_size);
// Center the window related to the device screen
assert(optimal_size.width <= window_size.width);
assert(optimal_size.height <= window_size.height);
uint32_t new_x = point.x + (window_size.width - optimal_size.width) / 2;
uint32_t new_y = point.y + (window_size.height - optimal_size.height) / 2;
get_optimal_window_size(screen, screen->content_size);
SDL_SetWindowSize(screen->window, optimal_size.width, optimal_size.height);
SDL_SetWindowPosition(screen->window, new_x, new_y);
LOGD("Resized to optimal size: %ux%u", optimal_size.width,
optimal_size.height);
}
@@ -742,7 +726,6 @@ screen_handle_event(struct screen *screen, SDL_Event *event) {
}
screen->maximized = false;
apply_pending_resize(screen);
screen_render(screen, true);
break;
}
return true;

View File

@@ -235,8 +235,6 @@ enable_tunnel_any_port(struct server *server, struct sc_port_range port_range,
static const char *
log_level_to_server_string(enum sc_log_level level) {
switch (level) {
case SC_LOG_LEVEL_VERBOSE:
return "verbose";
case SC_LOG_LEVEL_DEBUG:
return "debug";
case SC_LOG_LEVEL_INFO:

View File

@@ -104,38 +104,33 @@ static bool
stream_push_packet(struct stream *stream, AVPacket *packet) {
bool is_config = packet->pts == AV_NOPTS_VALUE;
// A config packet must not be decoded immediately (it contains no
// A config packet must not be decoded immetiately (it contains no
// frame); instead, it must be concatenated with the future data packet.
if (stream->pending || is_config) {
if (stream->has_pending || is_config) {
size_t offset;
if (stream->pending) {
offset = stream->pending->size;
if (av_grow_packet(stream->pending, packet->size)) {
if (stream->has_pending) {
offset = stream->pending.size;
if (av_grow_packet(&stream->pending, packet->size)) {
LOGE("Could not grow packet");
return false;
}
} else {
offset = 0;
stream->pending = av_packet_alloc();
if (!stream->pending) {
LOGE("Could not allocate packet");
return false;
}
if (av_new_packet(stream->pending, packet->size)) {
if (av_new_packet(&stream->pending, packet->size)) {
LOGE("Could not create packet");
av_packet_free(&stream->pending);
return false;
}
stream->has_pending = true;
}
memcpy(stream->pending->data + offset, packet->data, packet->size);
memcpy(stream->pending.data + offset, packet->data, packet->size);
if (!is_config) {
// prepare the concat packet to send to the decoder
stream->pending->pts = packet->pts;
stream->pending->dts = packet->dts;
stream->pending->flags = packet->flags;
packet = stream->pending;
stream->pending.pts = packet->pts;
stream->pending.dts = packet->dts;
stream->pending.flags = packet->flags;
packet = &stream->pending;
}
}
@@ -149,10 +144,10 @@ stream_push_packet(struct stream *stream, AVPacket *packet) {
// data packet
bool ok = stream_parse(stream, packet);
if (stream->pending) {
if (stream->has_pending) {
// the pending packet must be discarded (consumed or error)
av_packet_unref(stream->pending);
av_packet_free(&stream->pending);
stream->has_pending = false;
av_packet_unref(&stream->pending);
}
if (!ok) {
@@ -220,21 +215,16 @@ run_stream(void *data) {
// It's more complicated, but this allows to reduce the latency by 1 frame!
stream->parser->flags |= PARSER_FLAG_COMPLETE_FRAMES;
AVPacket *packet = av_packet_alloc();
if (!packet) {
LOGE("Could not allocate packet");
goto finally_close_parser;
}
for (;;) {
bool ok = stream_recv_packet(stream, packet);
AVPacket packet;
bool ok = stream_recv_packet(stream, &packet);
if (!ok) {
// end of stream
break;
}
ok = stream_push_packet(stream, packet);
av_packet_unref(packet);
ok = stream_push_packet(stream, &packet);
av_packet_unref(&packet);
if (!ok) {
// cannot process packet (error already logged)
break;
@@ -243,13 +233,10 @@ run_stream(void *data) {
LOGD("End of frames");
if (stream->pending) {
av_packet_unref(stream->pending);
av_packet_free(&stream->pending);
if (stream->has_pending) {
av_packet_unref(&stream->pending);
}
av_packet_free(&packet);
finally_close_parser:
av_parser_close(stream->parser);
finally_close_sinks:
stream_close_sinks(stream);
@@ -265,7 +252,7 @@ void
stream_init(struct stream *stream, socket_t socket,
const struct stream_callbacks *cbs, void *cbs_userdata) {
stream->socket = socket;
stream->pending = NULL;
stream->has_pending = false;
stream->sink_count = 0;
assert(cbs && cbs->on_eos);

View File

@@ -24,7 +24,8 @@ struct stream {
AVCodecParserContext *parser;
// successive packets may need to be concatenated, until a non-config
// packet is available
AVPacket *pending;
bool has_pending;
AVPacket pending;
const struct stream_callbacks *cbs;
void *cbs_userdata;

View File

@@ -1,53 +0,0 @@
#include "log.h"
#include <assert.h>
static SDL_LogPriority
log_level_sc_to_sdl(enum sc_log_level level) {
switch (level) {
case SC_LOG_LEVEL_VERBOSE:
return SDL_LOG_PRIORITY_VERBOSE;
case SC_LOG_LEVEL_DEBUG:
return SDL_LOG_PRIORITY_DEBUG;
case SC_LOG_LEVEL_INFO:
return SDL_LOG_PRIORITY_INFO;
case SC_LOG_LEVEL_WARN:
return SDL_LOG_PRIORITY_WARN;
case SC_LOG_LEVEL_ERROR:
return SDL_LOG_PRIORITY_ERROR;
default:
assert(!"unexpected log level");
return SDL_LOG_PRIORITY_INFO;
}
}
static enum sc_log_level
log_level_sdl_to_sc(SDL_LogPriority priority) {
switch (priority) {
case SDL_LOG_PRIORITY_VERBOSE:
return SC_LOG_LEVEL_VERBOSE;
case SDL_LOG_PRIORITY_DEBUG:
return SC_LOG_LEVEL_DEBUG;
case SDL_LOG_PRIORITY_INFO:
return SC_LOG_LEVEL_INFO;
case SDL_LOG_PRIORITY_WARN:
return SC_LOG_LEVEL_WARN;
case SDL_LOG_PRIORITY_ERROR:
return SC_LOG_LEVEL_ERROR;
default:
assert(!"unexpected log level");
return SC_LOG_LEVEL_INFO;
}
}
void
sc_set_log_level(enum sc_log_level level) {
SDL_LogPriority sdl_log = log_level_sc_to_sdl(level);
SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, sdl_log);
}
enum sc_log_level
sc_get_log_level(void) {
SDL_LogPriority sdl_log = SDL_LogGetPriority(SDL_LOG_CATEGORY_APPLICATION);
return log_level_sdl_to_sc(sdl_log);
}

View File

@@ -1,12 +1,8 @@
#ifndef SC_LOG_H
#define SC_LOG_H
#include "common.h"
#ifndef LOG_H
#define LOG_H
#include <SDL2/SDL_log.h>
#include "scrcpy.h"
#define LOGV(...) SDL_LogVerbose(SDL_LOG_CATEGORY_APPLICATION, __VA_ARGS__)
#define LOGD(...) SDL_LogDebug(SDL_LOG_CATEGORY_APPLICATION, __VA_ARGS__)
#define LOGI(...) SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, __VA_ARGS__)
@@ -14,10 +10,4 @@
#define LOGE(...) SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, __VA_ARGS__)
#define LOGC(...) SDL_LogCritical(SDL_LOG_CATEGORY_APPLICATION, __VA_ARGS__)
void
sc_set_log_level(enum sc_log_level level);
enum sc_log_level
sc_get_log_level(void);
#endif

View File

@@ -86,7 +86,7 @@ encode_and_write_frame(struct sc_v4l2_sink *vs, const AVFrame *frame) {
return false;
}
AVPacket *packet = vs->packet;
AVPacket *packet = &vs->packet;
ret = avcodec_receive_packet(vs->encoder_ctx, packet);
if (ret == 0) {
// A packet was received
@@ -235,17 +235,11 @@ sc_v4l2_sink_open(struct sc_v4l2_sink *vs) {
goto error_avcodec_close;
}
vs->packet = av_packet_alloc();
if (!vs->packet) {
LOGE("Could not allocate packet");
goto error_av_frame_free;
}
LOGD("Starting v4l2 thread");
ok = sc_thread_create(&vs->thread, run_v4l2_sink, "v4l2", vs);
if (!ok) {
LOGC("Could not start v4l2 thread");
goto error_av_packet_free;
goto error_av_frame_free;
}
vs->header_written = false;
@@ -255,8 +249,6 @@ sc_v4l2_sink_open(struct sc_v4l2_sink *vs) {
return true;
error_av_packet_free:
av_packet_free(&vs->packet);
error_av_frame_free:
av_frame_free(&vs->frame);
error_avcodec_close:
@@ -286,7 +278,6 @@ sc_v4l2_sink_close(struct sc_v4l2_sink *vs) {
sc_thread_join(&vs->thread, NULL);
av_packet_free(&vs->packet);
av_frame_free(&vs->frame);
avcodec_close(vs->encoder_ctx);
avcodec_free_context(&vs->encoder_ctx);

View File

@@ -26,7 +26,7 @@ struct sc_v4l2_sink {
bool header_written;
AVFrame *frame;
AVPacket *packet;
AVPacket packet;
};
bool

View File

@@ -12,7 +12,7 @@ public final class Ln {
private static final String PREFIX = "[server] ";
enum Level {
VERBOSE, DEBUG, INFO, WARN, ERROR
DEBUG, INFO, WARN, ERROR
}
private static Level threshold = Level.INFO;
@@ -36,13 +36,6 @@ public final class Ln {
return level.ordinal() >= threshold.ordinal();
}
public static void v(String message) {
if (isEnabled(Level.VERBOSE)) {
Log.v(TAG, message);
System.out.println(PREFIX + "VERBOSE: " + message);
}
}
public static void d(String message) {
if (isEnabled(Level.DEBUG)) {
Log.d(TAG, message);

View File

@@ -2,7 +2,6 @@ package com.genymobile.scrcpy.wrappers;
import com.genymobile.scrcpy.Ln;
import android.annotation.SuppressLint;
import android.os.Bundle;
import android.os.IBinder;
@@ -38,8 +37,6 @@ public class ContentProvider implements Closeable {
private Method callMethod;
private int callMethodVersion;
private Object attributionSource;
ContentProvider(ActivityManager manager, Object provider, String name, IBinder token) {
this.manager = manager;
this.provider = provider;
@@ -47,58 +44,36 @@ public class ContentProvider implements Closeable {
this.token = token;
}
@SuppressLint("PrivateApi")
private Method getCallMethod() throws NoSuchMethodException {
if (callMethod == null) {
try {
Class<?> attributionSourceClass = Class.forName("android.content.AttributionSource");
callMethod = provider.getClass().getMethod("call", attributionSourceClass, String.class, String.class, String.class, Bundle.class);
callMethod = provider.getClass()
.getMethod("call", String.class, String.class, String.class, String.class, String.class, Bundle.class);
callMethodVersion = 0;
} catch (NoSuchMethodException | ClassNotFoundException e0) {
} catch (NoSuchMethodException e) {
// old versions
try {
callMethod = provider.getClass()
.getMethod("call", String.class, String.class, String.class, String.class, String.class, Bundle.class);
callMethod = provider.getClass().getMethod("call", String.class, String.class, String.class, String.class, Bundle.class);
callMethodVersion = 1;
} catch (NoSuchMethodException e1) {
try {
callMethod = provider.getClass().getMethod("call", String.class, String.class, String.class, String.class, Bundle.class);
callMethodVersion = 2;
} catch (NoSuchMethodException e2) {
callMethod = provider.getClass().getMethod("call", String.class, String.class, String.class, Bundle.class);
callMethodVersion = 3;
}
} catch (NoSuchMethodException e2) {
callMethod = provider.getClass().getMethod("call", String.class, String.class, String.class, Bundle.class);
callMethodVersion = 2;
}
}
}
return callMethod;
}
@SuppressLint("PrivateApi")
private Object getAttributionSource()
throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
if (attributionSource == null) {
Class<?> cl = Class.forName("android.content.AttributionSource$Builder");
Object builder = cl.getConstructor(int.class).newInstance(ServiceManager.USER_ID);
cl.getDeclaredMethod("setPackageName", String.class).invoke(builder, ServiceManager.PACKAGE_NAME);
attributionSource = cl.getDeclaredMethod("build").invoke(builder);
}
return attributionSource;
}
private Bundle call(String callMethod, String arg, Bundle extras) {
try {
Method method = getCallMethod();
Object[] args;
switch (callMethodVersion) {
case 0:
args = new Object[]{getAttributionSource(), "settings", callMethod, arg, extras};
break;
case 1:
args = new Object[]{ServiceManager.PACKAGE_NAME, null, "settings", callMethod, arg, extras};
break;
case 2:
case 1:
args = new Object[]{ServiceManager.PACKAGE_NAME, "settings", callMethod, arg, extras};
break;
default:
@@ -106,7 +81,7 @@ public class ContentProvider implements Closeable {
break;
}
return (Bundle) method.invoke(provider, args);
} catch (InvocationTargetException | IllegalAccessException | NoSuchMethodException | ClassNotFoundException | InstantiationException e) {
} catch (InvocationTargetException | IllegalAccessException | NoSuchMethodException e) {
Ln.e("Could not invoke method", e);
return null;
}