Skip to content

Commit fe1613a

Browse files
author
Jonathan Matthew
committed
removable-media-manager: rework Android detection
Since there are very few new MTP devices being made that aren't using the Android MTP implementation (but not none), it makes sense to assume any MTP device we see is Android based unless we know otherwise. To do this, if built with libmtp, we only treat a device as non-Android if it matches an entry in the libmtp device list that doesn't have the set of flags applied to all Android devices. This means we don't need to keep a manually updated list of Android vendor and device names.
1 parent 12f5927 commit fe1613a

File tree

4 files changed

+87
-38
lines changed

4 files changed

+87
-38
lines changed

config.h.meson

+3
Original file line numberDiff line numberDiff line change
@@ -34,3 +34,6 @@
3434

3535
/* Define if pthread_getname_np is available. */
3636
#mesondefine HAVE_PTHREAD_GETNAME_NP
37+
38+
/* Define if libmtp support is enabled */
39+
#mesondefine WITH_LIBMTP

meson.build

+1
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,7 @@ endif
210210

211211
libmtp = dependency('libmtp', version: '>= 0.3.0', required: get_option('mtp'))
212212
if libmtp.found()
213+
cdata.set('WITH_LIBMTP', 1)
213214
if gudev.found()
214215
plugins += 'mtpdevice'
215216
elif get_option('mtp').enabled()

shell/meson.build

+1-1
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ librhythmbox_core = shared_library('rhythmbox-core',
9191
c_args: shell_c_args,
9292
include_directories: rhythmbox_core_include_directories,
9393
dependencies: [common_deps, mediaplayerid_dep, librb_dep, rhythmdb_dep,
94-
rbbackends_dep, rbmetadata_dep, rbpodcast_dep, rbwidgets_dep, sources_dep],
94+
rbbackends_dep, rbmetadata_dep, rbpodcast_dep, rbwidgets_dep, sources_dep, libmtp],
9595
install: true,
9696
link_whole: [librb, rbwidgets_lib, sources_lib],
9797
version: '@0@.@1@.@2@'.format(RHYTHMBOX_CORE_CURRENT, RHYTHMBOX_CORE_REVISION, RHYTHMBOX_CORE_AGE)

shell/rb-removable-media-manager.c

+82-37
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,29 @@
4444
#if defined(HAVE_GUDEV)
4545
#define G_UDEV_API_IS_SUBJECT_TO_CHANGE
4646
#include <gudev/gudev.h>
47-
#endif
47+
48+
#if defined(WITH_LIBMTP)
49+
#include <libmtp.h>
50+
51+
/* bug flags set for Android devices */
52+
#define DEVICE_FLAG_UNLOAD_DRIVER 0x00000002
53+
#define DEVICE_FLAG_BROKEN_MTPGETOBJPROPLIST 0x00000004
54+
#define DEVICE_FLAG_BROKEN_SET_OBJECT_PROPLIST 0x00000100
55+
#define DEVICE_FLAG_BROKEN_SEND_OBJECT_PROPLIST 0x00008000
56+
#define DEVICE_FLAG_LONG_TIMEOUT 0x08000000
57+
#define DEVICE_FLAG_FORCE_RESET_ON_CLOSE 0x10000000
58+
59+
/* Nexus/Pixel (MTP) (1831:4ee1) masks off BROKEN_MTPGETOBJPROPLIST */
60+
#define DEVICE_FLAGS_ANDROID_BUGS (\
61+
/*DEVICE_FLAG_BROKEN_MTPGETOBJPROPLIST |*/ \
62+
DEVICE_FLAG_BROKEN_SET_OBJECT_PROPLIST | \
63+
DEVICE_FLAG_BROKEN_SEND_OBJECT_PROPLIST | \
64+
DEVICE_FLAG_UNLOAD_DRIVER | \
65+
DEVICE_FLAG_LONG_TIMEOUT | \
66+
DEVICE_FLAG_FORCE_RESET_ON_CLOSE)
67+
68+
#endif /* WITH_LIBMTP */
69+
#endif /* HAVE_GUDEV */
4870

4971
#include "rb-removable-media-manager.h"
5072
#include "rb-library-source.h"
@@ -917,6 +939,21 @@ rb_removable_media_manager_get_gudev_device (RBRemovableMediaManager *manager, G
917939
#endif
918940
}
919941

942+
#if defined(HAVE_GUDEV)
943+
static int
944+
get_property_as_int (GUdevDevice *device, const char *property, int base)
945+
{
946+
const char *strvalue;
947+
948+
strvalue = g_udev_device_get_property (device, property);
949+
if (strvalue == NULL) {
950+
return 0;
951+
}
952+
953+
return strtol (strvalue, NULL, base);
954+
}
955+
#endif
956+
920957
/**
921958
* rb_removable_media_manager_device_is_android:
922959
* @manager: the #RBRemovableMediaManager
@@ -927,50 +964,58 @@ rb_removable_media_manager_get_gudev_device (RBRemovableMediaManager *manager, G
927964
* Return value: %TRUE if the device appears to be Android-based
928965
*/
929966
gboolean
930-
rb_removable_media_manager_device_is_android (RBRemovableMediaManager *manager, GObject *device)
967+
rb_removable_media_manager_device_is_android (RBRemovableMediaManager *manager, GObject *gdevice)
931968
{
932-
#if defined(HAVE_GUDEV)
933-
gboolean match;
934-
const char *model;
935-
const char *vendor;
969+
#if !defined(HAVE_GUDEV)
970+
return TRUE;
971+
#else
972+
GUdevDevice *device = G_UDEV_DEVICE (gdevice);
973+
#if defined(WITH_LIBMTP)
974+
LIBMTP_device_entry_t *device_list;
975+
int numdevs;
936976
int i;
977+
#endif
978+
int vendor;
979+
int model;
937980

938-
const char *androids[] = {
939-
"Android",
940-
"Nexus",
941-
"Pixel",
942-
"Nexus_5X"
943-
};
944-
const char *android_vendors[] = {
945-
"motorola",
946-
"OnePlus",
947-
"Google",
948-
"bq",
949-
"HMD_Global",
950-
"LENOVO",
951-
"asus",
952-
};
981+
if (g_strcmp0 (g_udev_device_get_subsystem (device), "usb") != 0) {
982+
rb_debug ("device %s is not a USB device", g_udev_device_get_name (device));
983+
return FALSE;
984+
}
953985

954-
match = FALSE;
986+
/* check that it's not an iPhone or iPod Touch */
987+
if (g_udev_device_get_property_as_boolean (device, "USBMUX_SUPPORTED")) {
988+
rb_debug ("device %s is supported through AFC, ignore", g_udev_device_get_name (device));
989+
return FALSE;
990+
}
955991

956-
model = g_udev_device_get_property (G_UDEV_DEVICE (device), "ID_MODEL");
957-
if (model != NULL) {
958-
for (i = 0; i < G_N_ELEMENTS (androids); i++) {
959-
if (strstr (model, androids[i]))
960-
match = TRUE;
961-
}
992+
if (g_udev_device_has_property (device, "ID_MTP_DEVICE") == FALSE) {
993+
rb_debug ("device %s does not support mtp, ignore", g_udev_device_get_name (device));
994+
return FALSE;
962995
}
963996

964-
vendor = g_udev_device_get_property (G_UDEV_DEVICE (device), "ID_VENDOR");
965-
if (vendor != NULL) {
966-
for (i = 0; i < G_N_ELEMENTS (android_vendors); i++) {
967-
if (strstr (vendor, android_vendors[i]))
968-
match = TRUE;
997+
vendor = get_property_as_int (device, "ID_VENDOR_ID", 16);
998+
model = get_property_as_int (device, "ID_MODEL_ID", 16);
999+
#if defined(WITH_LIBMTP)
1000+
1001+
rb_debug ("matching device %x:%x against libmtp device list", vendor, model);
1002+
LIBMTP_Get_Supported_Devices_List(&device_list, &numdevs);
1003+
for (i = 0; i < numdevs; i++) {
1004+
if (device_list[i].vendor_id == vendor &&
1005+
device_list[i].product_id == model) {
1006+
rb_debug ("matched libmtp device vendor %s product %s", device_list[i].vendor, device_list[i].product);
1007+
if ((device_list[i].device_flags & DEVICE_FLAGS_ANDROID_BUGS) != DEVICE_FLAGS_ANDROID_BUGS) {
1008+
rb_debug ("device doesn't have all android bug flags set");
1009+
return FALSE;
1010+
} else {
1011+
rb_debug ("device has android bug flags set");
1012+
return TRUE;
1013+
}
9691014
}
9701015
}
971-
972-
return match;
973-
#else
974-
return FALSE;
1016+
#endif
1017+
rb_debug ("unable to match device %x:%x against device list, assuming android", vendor, model);
1018+
return TRUE;
9751019
#endif
9761020
}
1021+

0 commit comments

Comments
 (0)