mirror of
https://github.com/KDE/kdeconnect-android
synced 2025-08-30 05:37:43 +00:00
refactor: migrate KdeConnect
to Kotlin
Migrate `KdeConnect` Application class into Kotlin. Already tested.
This commit is contained in:
parent
66877d6730
commit
eed7cad329
@ -1,204 +0,0 @@
|
|||||||
/*
|
|
||||||
* SPDX-FileCopyrightText: 2023 Albert Vaca Cintora <albertvaka@gmail.com>
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.kde.kdeconnect;
|
|
||||||
|
|
||||||
import android.Manifest;
|
|
||||||
import android.app.Application;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.SharedPreferences;
|
|
||||||
import android.content.pm.PackageManager;
|
|
||||||
import android.os.Build;
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.core.app.ActivityCompat;
|
|
||||||
import androidx.core.content.ContextCompat;
|
|
||||||
|
|
||||||
import org.kde.kdeconnect.Backends.BaseLink;
|
|
||||||
import org.kde.kdeconnect.Backends.BaseLinkProvider;
|
|
||||||
import org.kde.kdeconnect.Helpers.DeviceHelper;
|
|
||||||
import org.kde.kdeconnect.Helpers.LifecycleHelper;
|
|
||||||
import org.kde.kdeconnect.Helpers.NotificationHelper;
|
|
||||||
import org.kde.kdeconnect.Helpers.SecurityHelpers.RsaHelper;
|
|
||||||
import org.kde.kdeconnect.Helpers.SecurityHelpers.SslHelper;
|
|
||||||
import org.kde.kdeconnect.Plugins.Plugin;
|
|
||||||
import org.kde.kdeconnect.Plugins.PluginFactory;
|
|
||||||
import org.kde.kdeconnect.UserInterface.MainActivity;
|
|
||||||
import org.kde.kdeconnect.UserInterface.ThemeUtil;
|
|
||||||
import org.kde.kdeconnect_tp.BuildConfig;
|
|
||||||
import org.slf4j.impl.HandroidLoggerAdapter;
|
|
||||||
|
|
||||||
import java.security.cert.CertificateException;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This class holds all the active devices and makes them accessible from every other class.
|
|
||||||
* It also takes care of initializing all classes that need so when the app boots.
|
|
||||||
* It provides a ConnectionReceiver that the BackgroundService uses to ping this class every time a new DeviceLink is created.
|
|
||||||
*/
|
|
||||||
public class KdeConnect extends Application {
|
|
||||||
|
|
||||||
public interface DeviceListChangedCallback {
|
|
||||||
void onDeviceListChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static KdeConnect instance = null;
|
|
||||||
|
|
||||||
private final ConcurrentHashMap<String, Device> devices = new ConcurrentHashMap<>();
|
|
||||||
|
|
||||||
private final ConcurrentHashMap<String, DeviceListChangedCallback> deviceListChangedCallbacks = new ConcurrentHashMap<>();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onCreate() {
|
|
||||||
super.onCreate();
|
|
||||||
instance = this;
|
|
||||||
setupSL4JLogging();
|
|
||||||
Log.d("KdeConnect/Application", "onCreate");
|
|
||||||
ThemeUtil.setUserPreferredTheme(this);
|
|
||||||
DeviceHelper.initializeDeviceId(this);
|
|
||||||
RsaHelper.initialiseRsaKeys(this);
|
|
||||||
SslHelper.initialiseCertificate(this);
|
|
||||||
PluginFactory.initPluginInfo(this);
|
|
||||||
NotificationHelper.initializeChannels(this);
|
|
||||||
LifecycleHelper.initializeObserver();
|
|
||||||
loadRememberedDevicesFromSettings();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setupSL4JLogging() {
|
|
||||||
HandroidLoggerAdapter.DEBUG = BuildConfig.DEBUG;
|
|
||||||
HandroidLoggerAdapter.ANDROID_API_LEVEL = Build.VERSION.SDK_INT;
|
|
||||||
HandroidLoggerAdapter.APP_NAME = "KDEConnect";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onTerminate() {
|
|
||||||
Log.d("KdeConnect/Application", "onTerminate");
|
|
||||||
super.onTerminate();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addDeviceListChangedCallback(String key, DeviceListChangedCallback callback) {
|
|
||||||
deviceListChangedCallbacks.put(key, callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void removeDeviceListChangedCallback(String key) {
|
|
||||||
deviceListChangedCallbacks.remove(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void onDeviceListChanged() {
|
|
||||||
Log.i("MainActivity","Device list changed, notifying "+ deviceListChangedCallbacks.size() +" observers.");
|
|
||||||
for (DeviceListChangedCallback callback : deviceListChangedCallbacks.values()) {
|
|
||||||
callback.onDeviceListChanged();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public ConcurrentHashMap<String, Device> getDevices() {
|
|
||||||
return devices;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Device getDevice(String id) {
|
|
||||||
if (id == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return devices.get(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
public <T extends Plugin> T getDevicePlugin(String deviceId, Class<T> pluginClass) {
|
|
||||||
if (deviceId == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
Device device = devices.get(deviceId);
|
|
||||||
if (device == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return device.getPlugin(pluginClass);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static KdeConnect getInstance() {
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void loadRememberedDevicesFromSettings() {
|
|
||||||
//Log.e("BackgroundService", "Loading remembered trusted devices");
|
|
||||||
SharedPreferences preferences = getSharedPreferences("trusted_devices", Context.MODE_PRIVATE);
|
|
||||||
Set<String> trustedDevices = preferences.getAll().keySet();
|
|
||||||
for (String deviceId : trustedDevices) {
|
|
||||||
//Log.e("BackgroundService", "Loading device "+deviceId);
|
|
||||||
if (preferences.getBoolean(deviceId, false)) {
|
|
||||||
try {
|
|
||||||
Device device = new Device(this, deviceId);
|
|
||||||
devices.put(deviceId, device);
|
|
||||||
device.addPairingCallback(devicePairingCallback);
|
|
||||||
} catch (CertificateException e) {
|
|
||||||
Log.w("KdeConnect", "Couldn't load the certificate for a remembered device. Removing from trusted list.");
|
|
||||||
e.printStackTrace();
|
|
||||||
preferences.edit().remove(deviceId).apply();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private final PairingHandler.PairingCallback devicePairingCallback = new PairingHandler.PairingCallback() {
|
|
||||||
@Override
|
|
||||||
public void incomingPairRequest() {
|
|
||||||
onDeviceListChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void pairingSuccessful() {
|
|
||||||
onDeviceListChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void pairingFailed(String error) {
|
|
||||||
onDeviceListChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void unpaired() {
|
|
||||||
onDeviceListChanged();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
private final BaseLinkProvider.ConnectionReceiver connectionListener = new BaseLinkProvider.ConnectionReceiver() {
|
|
||||||
@Override
|
|
||||||
public void onConnectionReceived(@NonNull final BaseLink link) {
|
|
||||||
Device device = devices.get(link.getDeviceId());
|
|
||||||
if (device != null) {
|
|
||||||
device.addLink(link);
|
|
||||||
} else {
|
|
||||||
device = new Device(KdeConnect.this, link);
|
|
||||||
devices.put(link.getDeviceId(), device);
|
|
||||||
device.addPairingCallback(devicePairingCallback);
|
|
||||||
}
|
|
||||||
onDeviceListChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onConnectionLost(BaseLink link) {
|
|
||||||
Device device = devices.get(link.getDeviceId());
|
|
||||||
Log.i("KDE/onConnectionLost", "removeLink, deviceId: " + link.getDeviceId());
|
|
||||||
if (device != null) {
|
|
||||||
device.removeLink(link);
|
|
||||||
if (!device.isReachable() && !device.isPaired()) {
|
|
||||||
//Log.e("onConnectionLost","Removing connection device because it was not paired");
|
|
||||||
devices.remove(link.getDeviceId());
|
|
||||||
device.removePairingCallback(devicePairingCallback);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Log.d("KDE/onConnectionLost","Removing connection to unknown device");
|
|
||||||
}
|
|
||||||
onDeviceListChanged();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
public BaseLinkProvider.ConnectionReceiver getConnectionListener() {
|
|
||||||
return connectionListener;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
169
src/org/kde/kdeconnect/KdeConnect.kt
Normal file
169
src/org/kde/kdeconnect/KdeConnect.kt
Normal file
@ -0,0 +1,169 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2023 Albert Vaca Cintora <albertvaka@gmail.com>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||||
|
*/
|
||||||
|
package org.kde.kdeconnect
|
||||||
|
|
||||||
|
import android.app.Application
|
||||||
|
import android.os.Build
|
||||||
|
import android.util.Log
|
||||||
|
import org.kde.kdeconnect.Backends.BaseLink
|
||||||
|
import org.kde.kdeconnect.Backends.BaseLinkProvider.ConnectionReceiver
|
||||||
|
import org.kde.kdeconnect.Helpers.DeviceHelper
|
||||||
|
import org.kde.kdeconnect.Helpers.LifecycleHelper
|
||||||
|
import org.kde.kdeconnect.Helpers.NotificationHelper
|
||||||
|
import org.kde.kdeconnect.Helpers.SecurityHelpers.RsaHelper
|
||||||
|
import org.kde.kdeconnect.Helpers.SecurityHelpers.SslHelper
|
||||||
|
import org.kde.kdeconnect.PairingHandler.PairingCallback
|
||||||
|
import org.kde.kdeconnect.Plugins.Plugin
|
||||||
|
import org.kde.kdeconnect.Plugins.PluginFactory
|
||||||
|
import org.kde.kdeconnect.UserInterface.ThemeUtil
|
||||||
|
import org.kde.kdeconnect_tp.BuildConfig
|
||||||
|
import org.slf4j.impl.HandroidLoggerAdapter
|
||||||
|
import java.security.cert.CertificateException
|
||||||
|
import java.util.concurrent.ConcurrentHashMap
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This class holds all the active devices and makes them accessible from every other class.
|
||||||
|
* It also takes care of initializing all classes that need so when the app boots.
|
||||||
|
* It provides a ConnectionReceiver that the BackgroundService uses to ping this class every time a new DeviceLink is created.
|
||||||
|
*/
|
||||||
|
class KdeConnect : Application() {
|
||||||
|
fun interface DeviceListChangedCallback {
|
||||||
|
fun onDeviceListChanged()
|
||||||
|
}
|
||||||
|
|
||||||
|
val devices: ConcurrentHashMap<String, Device> = ConcurrentHashMap()
|
||||||
|
|
||||||
|
private val deviceListChangedCallbacks = ConcurrentHashMap<String, DeviceListChangedCallback>()
|
||||||
|
|
||||||
|
override fun onCreate() {
|
||||||
|
super.onCreate()
|
||||||
|
_instance = this
|
||||||
|
setupSL4JLogging()
|
||||||
|
Log.d("KdeConnect/Application", "onCreate")
|
||||||
|
ThemeUtil.setUserPreferredTheme(this)
|
||||||
|
DeviceHelper.initializeDeviceId(this)
|
||||||
|
RsaHelper.initialiseRsaKeys(this)
|
||||||
|
SslHelper.initialiseCertificate(this)
|
||||||
|
PluginFactory.initPluginInfo(this)
|
||||||
|
NotificationHelper.initializeChannels(this)
|
||||||
|
LifecycleHelper.initializeObserver()
|
||||||
|
loadRememberedDevicesFromSettings()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setupSL4JLogging() {
|
||||||
|
HandroidLoggerAdapter.DEBUG = BuildConfig.DEBUG
|
||||||
|
HandroidLoggerAdapter.ANDROID_API_LEVEL = Build.VERSION.SDK_INT
|
||||||
|
HandroidLoggerAdapter.APP_NAME = "KDEConnect"
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onTerminate() {
|
||||||
|
Log.d("KdeConnect/Application", "onTerminate")
|
||||||
|
super.onTerminate()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun addDeviceListChangedCallback(key: String, callback: DeviceListChangedCallback) {
|
||||||
|
deviceListChangedCallbacks[key] = callback
|
||||||
|
}
|
||||||
|
|
||||||
|
fun removeDeviceListChangedCallback(key: String) {
|
||||||
|
deviceListChangedCallbacks.remove(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun onDeviceListChanged() {
|
||||||
|
Log.i("MainActivity", "Device list changed, notifying ${deviceListChangedCallbacks.size} observers.")
|
||||||
|
deviceListChangedCallbacks.values.forEach(DeviceListChangedCallback::onDeviceListChanged)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getDevice(id: String?): Device? {
|
||||||
|
if (id == null) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
return devices[id]
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <T : Plugin> getDevicePlugin(deviceId: String?, pluginClass: Class<T>): T? {
|
||||||
|
val device = getDevice(deviceId)
|
||||||
|
return device?.getPlugin(pluginClass)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun loadRememberedDevicesFromSettings() {
|
||||||
|
// Log.e("BackgroundService", "Loading remembered trusted devices");
|
||||||
|
val preferences = getSharedPreferences("trusted_devices", MODE_PRIVATE)
|
||||||
|
val trustedDevices: Set<String> = preferences.all.keys
|
||||||
|
trustedDevices.map { id ->
|
||||||
|
Log.d("KdeConnect", "Loading device $id")
|
||||||
|
id
|
||||||
|
}.filter { preferences.getBoolean(it, false) }.forEach {
|
||||||
|
try {
|
||||||
|
val device = Device(this, it)
|
||||||
|
devices[it] = device
|
||||||
|
device.addPairingCallback(devicePairingCallback)
|
||||||
|
} catch (e: CertificateException) {
|
||||||
|
Log.w(
|
||||||
|
"KdeConnect",
|
||||||
|
"Couldn't load the certificate for a remembered device. Removing from trusted list.", e
|
||||||
|
)
|
||||||
|
preferences.edit().remove(it).apply()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val devicePairingCallback: PairingCallback = object : PairingCallback {
|
||||||
|
override fun incomingPairRequest() {
|
||||||
|
onDeviceListChanged()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun pairingSuccessful() {
|
||||||
|
onDeviceListChanged()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun pairingFailed(error: String) {
|
||||||
|
onDeviceListChanged()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun unpaired() {
|
||||||
|
onDeviceListChanged()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val connectionListener: ConnectionReceiver = object : ConnectionReceiver {
|
||||||
|
override fun onConnectionReceived(link: BaseLink) {
|
||||||
|
var device = devices[link.deviceId]
|
||||||
|
if (device != null) {
|
||||||
|
device.addLink(link)
|
||||||
|
} else {
|
||||||
|
device = Device(this@KdeConnect, link)
|
||||||
|
devices[link.deviceId] = device
|
||||||
|
device.addPairingCallback(devicePairingCallback)
|
||||||
|
}
|
||||||
|
onDeviceListChanged()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onConnectionLost(link: BaseLink) {
|
||||||
|
val device = devices[link.deviceId]
|
||||||
|
Log.i("KDE/onConnectionLost", "removeLink, deviceId: ${link.deviceId}")
|
||||||
|
if (device != null) {
|
||||||
|
device.removeLink(link)
|
||||||
|
if (!device.isReachable && !device.isPaired) {
|
||||||
|
// Log.e("onConnectionLost","Removing connection device because it was not paired");
|
||||||
|
devices.remove(link.deviceId)
|
||||||
|
device.removePairingCallback(devicePairingCallback)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Log.d("KDE/onConnectionLost", "Removing connection to unknown device")
|
||||||
|
}
|
||||||
|
onDeviceListChanged()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
@JvmStatic
|
||||||
|
private lateinit var _instance: KdeConnect
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun getInstance(): KdeConnect = _instance
|
||||||
|
}
|
||||||
|
}
|
@ -50,7 +50,7 @@ class PresenterActivity : AppCompatActivity(), SensorEventListener {
|
|||||||
}
|
}
|
||||||
private val powerManager by lazy { getSystemService(POWER_SERVICE) as PowerManager }
|
private val powerManager by lazy { getSystemService(POWER_SERVICE) as PowerManager }
|
||||||
private val plugin: PresenterPlugin by lazy {
|
private val plugin: PresenterPlugin by lazy {
|
||||||
KdeConnect.getInstance().getDevicePlugin(intent.getStringExtra("deviceId"), PresenterPlugin::class.java)
|
KdeConnect.getInstance().getDevicePlugin(intent.getStringExtra("deviceId"), PresenterPlugin::class.java)!!
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: make configurable
|
//TODO: make configurable
|
||||||
|
@ -286,7 +286,7 @@ class MainActivity : AppCompatActivity(), OnSharedPreferenceChangeListener {
|
|||||||
override fun onStart() {
|
override fun onStart() {
|
||||||
super.onStart()
|
super.onStart()
|
||||||
BackgroundService.Start(applicationContext)
|
BackgroundService.Start(applicationContext)
|
||||||
KdeConnect.getInstance().addDeviceListChangedCallback(this::class.simpleName) { runOnUiThread { updateDeviceList() } }
|
KdeConnect.getInstance().addDeviceListChangedCallback(this::class.simpleName!!) { runOnUiThread { updateDeviceList() } }
|
||||||
updateDeviceList()
|
updateDeviceList()
|
||||||
onBackPressedDispatcher.addCallback(mainFragmentCallback)
|
onBackPressedDispatcher.addCallback(mainFragmentCallback)
|
||||||
onBackPressedDispatcher.addCallback(closeDrawerCallback)
|
onBackPressedDispatcher.addCallback(closeDrawerCallback)
|
||||||
@ -294,7 +294,7 @@ class MainActivity : AppCompatActivity(), OnSharedPreferenceChangeListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onStop() {
|
override fun onStop() {
|
||||||
KdeConnect.getInstance().removeDeviceListChangedCallback(this::class.simpleName)
|
KdeConnect.getInstance().removeDeviceListChangedCallback(this::class.simpleName!!)
|
||||||
mainFragmentCallback.remove()
|
mainFragmentCallback.remove()
|
||||||
closeDrawerCallback.remove()
|
closeDrawerCallback.remove()
|
||||||
super.onStop()
|
super.onStop()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user