2
0
mirror of https://github.com/KDE/kdeconnect-android synced 2025-08-30 13:47:41 +00:00

Replace DeviceNames library

The version of the library we used stopped working in 2020 when the names
database it tries to download got deleted from the master branch of their
Github repo. There's a newer version, but it seems to have lost the
fetch-from-the-internet functionality (it only bundles a list of names) and
for some reason it crashes when I tested it (I've opened an issue on their
repo). Since Google now provides a CSV with all the Android device names
that exist, I've replaced the library by my own function that downloads the
CSV file (~3MB) in the first run of the app and looks for the name there.
This commit is contained in:
Albert Vaca Cintora
2023-05-27 00:49:38 +02:00
parent 476304d6fb
commit 0eb4b5bced
2 changed files with 56 additions and 24 deletions

View File

@@ -180,7 +180,6 @@ dependencies {
implementation 'androidx.gridlayout:gridlayout:1.0.0' implementation 'androidx.gridlayout:gridlayout:1.0.0'
implementation 'com.google.android.material:material:1.9.0' implementation 'com.google.android.material:material:1.9.0'
implementation 'com.jakewharton:disklrucache:2.0.2' //For caching album art bitmaps implementation 'com.jakewharton:disklrucache:2.0.2' //For caching album art bitmaps
implementation 'com.jaredrummler:android-device-names:1.1.9' //To get a human-friendly device name
implementation 'org.apache.sshd:sshd-core:0.14.0' implementation 'org.apache.sshd:sshd-core:0.14.0'
implementation 'org.apache.mina:mina-core:2.0.19' //For some reason, makes sshd-core:0.14.0 work without NIO, which isn't available until Android 8 (api 26) implementation 'org.apache.mina:mina-core:2.0.19' //For some reason, makes sshd-core:0.14.0 work without NIO, which isn't available until Android 8 (api 26)
@@ -203,6 +202,8 @@ dependencies {
implementation 'org.apache.commons:commons-collections4:4.4' implementation 'org.apache.commons:commons-collections4:4.4'
implementation 'org.apache.commons:commons-lang3:3.12.0' implementation 'org.apache.commons:commons-lang3:3.12.0'
implementation 'com.univocity:univocity-parsers:2.9.1'
// Kotlin // Kotlin
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutines_version" implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutines_version"

View File

@@ -11,14 +11,22 @@ import android.content.Context;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.content.res.Configuration; import android.content.res.Configuration;
import android.content.res.Resources; import android.content.res.Resources;
import android.os.Build;
import android.preference.PreferenceManager; import android.preference.PreferenceManager;
import android.provider.Settings; import android.provider.Settings;
import android.util.Log; import android.util.Log;
import com.jaredrummler.android.device.DeviceName; import com.univocity.parsers.csv.CsvParser;
import com.univocity.parsers.csv.CsvParserSettings;
import org.kde.kdeconnect.Device; import org.kde.kdeconnect.Device;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;
import java.nio.charset.StandardCharsets;
import java.util.Set; import java.util.Set;
import java.util.UUID; import java.util.UUID;
@@ -27,10 +35,13 @@ public class DeviceHelper {
public static final int ProtocolVersion = 7; public static final int ProtocolVersion = 7;
public static final String KEY_DEVICE_NAME_PREFERENCE = "device_name_preference"; public static final String KEY_DEVICE_NAME_PREFERENCE = "device_name_preference";
public static final String KEY_DEVICE_NAME_FETCHED_FROM_THE_INTERNET = "device_name_downloaded_preference";
public static final String KEY_DEVICE_ID_PREFERENCE = "device_id_preference"; public static final String KEY_DEVICE_ID_PREFERENCE = "device_id_preference";
private static boolean fetchingName = false; private static boolean fetchingName = false;
public static final String DEVICE_DATABASE = "https://storage.googleapis.com/play_public/supported_devices.csv";
private static boolean isTablet() { private static boolean isTablet() {
Configuration config = Resources.getSystem().getConfiguration(); Configuration config = Resources.getSystem().getConfiguration();
//This assumes that the values for the screen sizes are consecutive, so XXLARGE > XLARGE > LARGE //This assumes that the values for the screen sizes are consecutive, so XXLARGE > XLARGE > LARGE
@@ -52,35 +63,55 @@ public class DeviceHelper {
} }
} }
//It returns getAndroidDeviceName() if no user-defined name has been set with setDeviceName().
public static String getDeviceName(Context context) { public static String getDeviceName(Context context) {
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context); SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
// Could use preferences.contains but would need to check for empty String anyway. if (!preferences.contains(KEY_DEVICE_NAME_PREFERENCE)
String deviceName = preferences.getString(KEY_DEVICE_NAME_PREFERENCE, ""); && !preferences.getBoolean(KEY_DEVICE_NAME_FETCHED_FROM_THE_INTERNET, false)
if (deviceName.isEmpty()) { && !fetchingName) {
//DeviceName.init(context); // Needed in DeviceName 2.x + fetchingName = true;
if (!fetchingName) { DeviceHelper.backgroundFetchDeviceName(context);
fetchingName = true; return Build.MODEL;
DeviceHelper.backgroundFetchDeviceName(context); //Starts a background thread that will eventually update the shared pref
}
return DeviceName.getDeviceName(); //Temp name while we fetch it from the internet
} }
return deviceName; return preferences.getString(KEY_DEVICE_NAME_PREFERENCE, Build.MODEL);
} }
private static void backgroundFetchDeviceName(final Context context) { private static void backgroundFetchDeviceName(final Context context) {
DeviceName.with(context).request((info, error) -> { ThreadHelper.execute(() -> {
try {
URL url = new URL(DEVICE_DATABASE);
URLConnection connection = url.openConnection();
// If we get here we managed to download the file. Mark that as done so we don't try again even if we don't end up finding a name.
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
preferences.edit().putBoolean(KEY_DEVICE_NAME_FETCHED_FROM_THE_INTERNET, true).apply();
try (BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream(), StandardCharsets.UTF_16))) {
CsvParserSettings settings = new CsvParserSettings();
settings.setHeaderExtractionEnabled(true);
CsvParser parser = new CsvParser(settings);
boolean found = false;
for (String[] records : parser.iterate(reader)) {
if (records.length < 4) {
continue;
}
String buildModel = records[3];
if (Build.MODEL.equals(buildModel)) {
String deviceName = records[1];
Log.i("DeviceHelper", "Got device name: " + deviceName);
// Update the shared preference. Places that display the name should be listening to this change and update it
setDeviceName(context, deviceName);
found = true;
break;
}
}
if (!found) {
Log.e("DeviceHelper", "Didn't find a device name for " + Build.MODEL);
}
}
} catch(IOException e) {
e.printStackTrace();
}
fetchingName = false; fetchingName = false;
if (error != null) {
Log.e("DeviceHelper", "Error fetching device name");
error.printStackTrace();
}
if (info != null) {
String deviceName = info.getName();
Log.i("DeviceHelper", "Got device name: " + deviceName);
// Update the shared preference. Places that display the name should be listening to this change and update it
setDeviceName(context, deviceName);
}
}); });
} }