mirror of
https://github.com/KDE/kdeconnect-android
synced 2025-08-22 01:51:47 +00:00
Fix linter warnings
This commit is contained in:
parent
28070954a6
commit
fd51ec7c14
@ -24,13 +24,16 @@ import java.io.Reader
|
|||||||
import java.util.UUID
|
import java.util.UUID
|
||||||
import kotlin.text.Charsets.UTF_8
|
import kotlin.text.Charsets.UTF_8
|
||||||
|
|
||||||
class BluetoothLink(context: Context?, connection: ConnectionMultiplexer, input: InputStream, output: OutputStream, remoteAddress: BluetoothDevice, deviceInfo: DeviceInfo, linkProvider: BluetoothLinkProvider) : BaseLink(context!!, linkProvider) {
|
class BluetoothLink(
|
||||||
private val connection: ConnectionMultiplexer?
|
context: Context?,
|
||||||
private val input: InputStream
|
connection: ConnectionMultiplexer,
|
||||||
private val output: OutputStream
|
val input: InputStream,
|
||||||
private val remoteAddress: BluetoothDevice
|
val output: OutputStream,
|
||||||
private val linkProvider: BluetoothLinkProvider
|
val remoteAddress: BluetoothDevice,
|
||||||
private val deviceInfo: DeviceInfo
|
val theDeviceInfo: DeviceInfo,
|
||||||
|
val linkProvider: BluetoothLinkProvider
|
||||||
|
) : BaseLink(context!!, linkProvider) {
|
||||||
|
private val connection: ConnectionMultiplexer? = connection
|
||||||
private var continueAccepting = true
|
private var continueAccepting = true
|
||||||
private val receivingThread = Thread(object : Runnable {
|
private val receivingThread = Thread(object : Runnable {
|
||||||
override fun run() {
|
override fun run() {
|
||||||
@ -64,8 +67,7 @@ class BluetoothLink(context: Context?, connection: ConnectionMultiplexer, input:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun processMessage(message: String) {
|
private fun processMessage(message: String) {
|
||||||
val np: NetworkPacket
|
val np = try {
|
||||||
np = try {
|
|
||||||
NetworkPacket.unserialize(message)
|
NetworkPacket.unserialize(message)
|
||||||
} catch (e: JSONException) {
|
} catch (e: JSONException) {
|
||||||
Log.e("BluetoothLink/receiving", "Unable to parse message.", e)
|
Log.e("BluetoothLink/receiving", "Unable to parse message.", e)
|
||||||
@ -84,15 +86,6 @@ class BluetoothLink(context: Context?, connection: ConnectionMultiplexer, input:
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
init {
|
|
||||||
this.connection = connection
|
|
||||||
this.input = input
|
|
||||||
this.output = output
|
|
||||||
this.deviceInfo = deviceInfo
|
|
||||||
this.remoteAddress = remoteAddress
|
|
||||||
this.linkProvider = linkProvider
|
|
||||||
}
|
|
||||||
|
|
||||||
fun startListening() {
|
fun startListening() {
|
||||||
receivingThread.start()
|
receivingThread.start()
|
||||||
}
|
}
|
||||||
@ -102,7 +95,7 @@ class BluetoothLink(context: Context?, connection: ConnectionMultiplexer, input:
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun getDeviceInfo(): DeviceInfo {
|
override fun getDeviceInfo(): DeviceInfo {
|
||||||
return deviceInfo
|
return theDeviceInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun disconnect() {
|
override fun disconnect() {
|
||||||
|
@ -35,6 +35,7 @@ import java.io.Reader
|
|||||||
import java.security.cert.CertificateException
|
import java.security.cert.CertificateException
|
||||||
import java.util.UUID
|
import java.util.UUID
|
||||||
import kotlin.text.Charsets.UTF_8
|
import kotlin.text.Charsets.UTF_8
|
||||||
|
import androidx.core.content.edit
|
||||||
|
|
||||||
class BluetoothLinkProvider(private val context: Context) : BaseLinkProvider() {
|
class BluetoothLinkProvider(private val context: Context) : BaseLinkProvider() {
|
||||||
private val visibleDevices: MutableMap<String, BluetoothLink> = HashMap()
|
private val visibleDevices: MutableMap<String, BluetoothLink> = HashMap()
|
||||||
@ -138,9 +139,9 @@ class BluetoothLinkProvider(private val context: Context) : BaseLinkProvider() {
|
|||||||
} catch (e: SecurityException) {
|
} catch (e: SecurityException) {
|
||||||
Log.e("KDEConnect", "Security Exception for CONNECT", e)
|
Log.e("KDEConnect", "Security Exception for CONNECT", e)
|
||||||
|
|
||||||
val prefenceEditor = PreferenceManager.getDefaultSharedPreferences(context).edit()
|
PreferenceManager.getDefaultSharedPreferences(context).edit {
|
||||||
prefenceEditor.putBoolean(SettingsFragment.KEY_BLUETOOTH_ENABLED, false)
|
putBoolean(SettingsFragment.KEY_BLUETOOTH_ENABLED, false)
|
||||||
prefenceEditor.apply()
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,7 @@ import java.util.concurrent.locks.ReentrantLock
|
|||||||
import kotlin.concurrent.withLock
|
import kotlin.concurrent.withLock
|
||||||
|
|
||||||
class ConnectionMultiplexer(socket: BluetoothSocket) : Closeable {
|
class ConnectionMultiplexer(socket: BluetoothSocket) : Closeable {
|
||||||
private class ChannelInputStream constructor(val channel: Channel) : InputStream(), Closeable {
|
private class ChannelInputStream(val channel: Channel) : InputStream(), Closeable {
|
||||||
override fun available(): Int {
|
override fun available(): Int {
|
||||||
return channel.available()
|
return channel.available()
|
||||||
}
|
}
|
||||||
@ -49,7 +49,7 @@ class ConnectionMultiplexer(socket: BluetoothSocket) : Closeable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ChannelOutputStream constructor(val channel: Channel) : OutputStream(), Closeable {
|
private class ChannelOutputStream(val channel: Channel) : OutputStream(), Closeable {
|
||||||
@Throws(IOException::class)
|
@Throws(IOException::class)
|
||||||
override fun close() {
|
override fun close() {
|
||||||
channel.close()
|
channel.close()
|
||||||
@ -78,7 +78,7 @@ class ConnectionMultiplexer(socket: BluetoothSocket) : Closeable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class Channel constructor(val multiplexer: ConnectionMultiplexer, val id: UUID) : Closeable {
|
private class Channel(val multiplexer: ConnectionMultiplexer, val id: UUID) : Closeable {
|
||||||
val readBuffer: ByteBuffer = ByteBuffer.allocate(BUFFER_SIZE)
|
val readBuffer: ByteBuffer = ByteBuffer.allocate(BUFFER_SIZE)
|
||||||
val lock = ReentrantLock()
|
val lock = ReentrantLock()
|
||||||
var lockCondition: Condition = lock.newCondition()
|
var lockCondition: Condition = lock.newCondition()
|
||||||
@ -371,14 +371,9 @@ class ConnectionMultiplexer(socket: BluetoothSocket) : Closeable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private inner class ListenRunnable constructor(socket: BluetoothSocket) : Runnable {
|
private inner class ListenRunnable(socket: BluetoothSocket) : Runnable {
|
||||||
var input: InputStream
|
var input: InputStream = socket.inputStream
|
||||||
var output: OutputStream
|
var output: OutputStream = socket.outputStream
|
||||||
|
|
||||||
init {
|
|
||||||
input = socket.inputStream
|
|
||||||
output = socket.outputStream
|
|
||||||
}
|
|
||||||
|
|
||||||
@Throws(IOException::class)
|
@Throws(IOException::class)
|
||||||
private fun readBuffer(buffer: ByteArray, len: Int) {
|
private fun readBuffer(buffer: ByteArray, len: Int) {
|
||||||
|
@ -41,7 +41,7 @@ public class MdnsDiscovery {
|
|||||||
this.lanLinkProvider = lanLinkProvider;
|
this.lanLinkProvider = lanLinkProvider;
|
||||||
this.mNsdManager = (NsdManager) context.getSystemService(Context.NSD_SERVICE);
|
this.mNsdManager = (NsdManager) context.getSystemService(Context.NSD_SERVICE);
|
||||||
this.mNsdResolveQueue = new NsdResolveQueue(this.mNsdManager);
|
this.mNsdResolveQueue = new NsdResolveQueue(this.mNsdManager);
|
||||||
WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
|
WifiManager wifiManager = (WifiManager) context.getApplicationContext().getSystemService(Context.WIFI_SERVICE);
|
||||||
multicastLock = wifiManager.createMulticastLock("kdeConnectMdnsMulticastLock");
|
multicastLock = wifiManager.createMulticastLock("kdeConnectMdnsMulticastLock");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -132,7 +132,7 @@ public class MdnsDiscovery {
|
|||||||
// Also, on Android Lollipop those fields aren't resolved.
|
// Also, on Android Lollipop those fields aren't resolved.
|
||||||
String deviceName = DeviceHelper.getDeviceName(context);
|
String deviceName = DeviceHelper.getDeviceName(context);
|
||||||
String deviceType = DeviceHelper.getDeviceType().toString();
|
String deviceType = DeviceHelper.getDeviceType().toString();
|
||||||
String protocolVersion = Integer.toString(DeviceHelper.ProtocolVersion);
|
String protocolVersion = Integer.toString(DeviceHelper.PROTOCOL_VERSION);
|
||||||
serviceInfo.setAttribute("id", deviceId);
|
serviceInfo.setAttribute("id", deviceId);
|
||||||
serviceInfo.setAttribute("name", deviceName);
|
serviceInfo.setAttribute("name", deviceName);
|
||||||
serviceInfo.setAttribute("type", deviceType);
|
serviceInfo.setAttribute("type", deviceType);
|
||||||
|
@ -32,7 +32,6 @@ import org.kde.kdeconnect.Backends.BaseLinkProvider
|
|||||||
import org.kde.kdeconnect.Backends.BaseLinkProvider.ConnectionReceiver
|
import org.kde.kdeconnect.Backends.BaseLinkProvider.ConnectionReceiver
|
||||||
import org.kde.kdeconnect.Backends.BluetoothBackend.BluetoothLinkProvider
|
import org.kde.kdeconnect.Backends.BluetoothBackend.BluetoothLinkProvider
|
||||||
import org.kde.kdeconnect.Backends.LanBackend.LanLinkProvider
|
import org.kde.kdeconnect.Backends.LanBackend.LanLinkProvider
|
||||||
import org.kde.kdeconnect.Backends.LoopbackBackend.LoopbackLinkProvider
|
|
||||||
import org.kde.kdeconnect.Helpers.NotificationHelper
|
import org.kde.kdeconnect.Helpers.NotificationHelper
|
||||||
import org.kde.kdeconnect.Plugins.ClibpoardPlugin.ClipboardFloatingActivity
|
import org.kde.kdeconnect.Plugins.ClibpoardPlugin.ClipboardFloatingActivity
|
||||||
import org.kde.kdeconnect.Plugins.RunCommandPlugin.RunCommandActivity
|
import org.kde.kdeconnect.Plugins.RunCommandPlugin.RunCommandActivity
|
||||||
|
@ -33,7 +33,6 @@ import org.kde.kdeconnect.DeviceStats.countReceived
|
|||||||
import org.kde.kdeconnect.DeviceStats.countSent
|
import org.kde.kdeconnect.DeviceStats.countSent
|
||||||
import org.kde.kdeconnect.Helpers.DeviceHelper
|
import org.kde.kdeconnect.Helpers.DeviceHelper
|
||||||
import org.kde.kdeconnect.Helpers.NotificationHelper
|
import org.kde.kdeconnect.Helpers.NotificationHelper
|
||||||
import org.kde.kdeconnect.Helpers.SecurityHelpers.SslHelper
|
|
||||||
import org.kde.kdeconnect.PairingHandler.PairingCallback
|
import org.kde.kdeconnect.PairingHandler.PairingCallback
|
||||||
import org.kde.kdeconnect.Plugins.Plugin
|
import org.kde.kdeconnect.Plugins.Plugin
|
||||||
import org.kde.kdeconnect.Plugins.Plugin.Companion.getPluginKey
|
import org.kde.kdeconnect.Plugins.Plugin.Companion.getPluginKey
|
||||||
@ -46,6 +45,7 @@ import java.util.Vector
|
|||||||
import java.util.concurrent.ConcurrentHashMap
|
import java.util.concurrent.ConcurrentHashMap
|
||||||
import java.util.concurrent.ConcurrentMap
|
import java.util.concurrent.ConcurrentMap
|
||||||
import java.util.concurrent.CopyOnWriteArrayList
|
import java.util.concurrent.CopyOnWriteArrayList
|
||||||
|
import androidx.core.content.edit
|
||||||
|
|
||||||
class Device : PacketReceiver {
|
class Device : PacketReceiver {
|
||||||
|
|
||||||
@ -164,7 +164,7 @@ class Device : PacketReceiver {
|
|||||||
|
|
||||||
// Returns 0 if the version matches, < 0 if it is older or > 0 if it is newer
|
// Returns 0 if the version matches, < 0 if it is older or > 0 if it is newer
|
||||||
fun compareProtocolVersion(): Int =
|
fun compareProtocolVersion(): Int =
|
||||||
deviceInfo.protocolVersion - DeviceHelper.ProtocolVersion
|
deviceInfo.protocolVersion - DeviceHelper.PROTOCOL_VERSION
|
||||||
|
|
||||||
val isPaired: Boolean
|
val isPaired: Boolean
|
||||||
get() = pairingHandler.state == PairingHandler.PairState.Paired
|
get() = pairingHandler.state == PairingHandler.PairState.Paired
|
||||||
@ -209,7 +209,7 @@ class Device : PacketReceiver {
|
|||||||
|
|
||||||
// Store as trusted device
|
// Store as trusted device
|
||||||
val preferences = context.getSharedPreferences("trusted_devices", Context.MODE_PRIVATE)
|
val preferences = context.getSharedPreferences("trusted_devices", Context.MODE_PRIVATE)
|
||||||
preferences.edit().putBoolean(deviceInfo.id, true).apply()
|
preferences.edit { putBoolean(deviceInfo.id, true) }
|
||||||
|
|
||||||
try {
|
try {
|
||||||
reloadPluginsFromSettings()
|
reloadPluginsFromSettings()
|
||||||
@ -228,10 +228,10 @@ class Device : PacketReceiver {
|
|||||||
override fun unpaired() {
|
override fun unpaired() {
|
||||||
Log.i("Device", "unpaired, removing from trusted devices list")
|
Log.i("Device", "unpaired, removing from trusted devices list")
|
||||||
val preferences = context.getSharedPreferences("trusted_devices", Context.MODE_PRIVATE)
|
val preferences = context.getSharedPreferences("trusted_devices", Context.MODE_PRIVATE)
|
||||||
preferences.edit().remove(deviceInfo.id).apply()
|
preferences.edit { remove(deviceInfo.id) }
|
||||||
|
|
||||||
val devicePreferences = context.getSharedPreferences(deviceInfo.id, Context.MODE_PRIVATE)
|
val devicePreferences = context.getSharedPreferences(deviceInfo.id, Context.MODE_PRIVATE)
|
||||||
devicePreferences.edit().clear().apply()
|
devicePreferences.edit { clear() }
|
||||||
|
|
||||||
pairingCallbacks.forEach(PairingCallback::unpaired)
|
pairingCallbacks.forEach(PairingCallback::unpaired)
|
||||||
|
|
||||||
@ -596,7 +596,7 @@ class Device : PacketReceiver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun setPluginEnabled(pluginKey: String, value: Boolean) {
|
fun setPluginEnabled(pluginKey: String, value: Boolean) {
|
||||||
settings.edit().putBoolean(pluginKey, value).apply()
|
settings.edit { putBoolean(pluginKey, value) }
|
||||||
reloadPluginsFromSettings()
|
reloadPluginsFromSettings()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,12 +59,12 @@ class DeviceInfo(
|
|||||||
*/
|
*/
|
||||||
fun toIdentityPacket(): NetworkPacket =
|
fun toIdentityPacket(): NetworkPacket =
|
||||||
NetworkPacket(NetworkPacket.PACKET_TYPE_IDENTITY).also { np ->
|
NetworkPacket(NetworkPacket.PACKET_TYPE_IDENTITY).also { np ->
|
||||||
np.set("deviceId", id)
|
np["deviceId"] = id
|
||||||
np.set("deviceName", name)
|
np["deviceName"] = name
|
||||||
np.set("protocolVersion", protocolVersion)
|
np["protocolVersion"] = protocolVersion
|
||||||
np.set("deviceType", type.toString())
|
np["deviceType"] = type.toString()
|
||||||
np.set("incomingCapabilities", incomingCapabilities!!)
|
np["incomingCapabilities"] = incomingCapabilities!!
|
||||||
np.set("outgoingCapabilities", outgoingCapabilities!!)
|
np["outgoingCapabilities"] = outgoingCapabilities!!
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@ -107,10 +107,10 @@ class DeviceInfo(
|
|||||||
fun isValidIdentityPacket(identityPacket: NetworkPacket): Boolean = with(identityPacket) {
|
fun isValidIdentityPacket(identityPacket: NetworkPacket): Boolean = with(identityPacket) {
|
||||||
type == NetworkPacket.PACKET_TYPE_IDENTITY &&
|
type == NetworkPacket.PACKET_TYPE_IDENTITY &&
|
||||||
DeviceHelper.filterName(getString("deviceName", "")).isNotBlank() &&
|
DeviceHelper.filterName(getString("deviceName", "")).isNotBlank() &&
|
||||||
isValidDeviceId(getString("deviceId", ""));
|
isValidDeviceId(getString("deviceId", ""))
|
||||||
}
|
}
|
||||||
|
|
||||||
private val DEVICE_ID_REGEX = "^[a-zA-Z0-9_-]{32,38}\$".toRegex()
|
private val DEVICE_ID_REGEX = "^[a-zA-Z0-9_-]{32,38}$".toRegex()
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun isValidDeviceId(deviceId: String): Boolean = deviceId.matches(DEVICE_ID_REGEX)
|
fun isValidDeviceId(deviceId: String): Boolean = deviceId.matches(DEVICE_ID_REGEX)
|
||||||
|
@ -115,7 +115,7 @@ object DeviceStats {
|
|||||||
val entry = iterator.next()
|
val entry = iterator.next()
|
||||||
val events = entry.value
|
val events = entry.value
|
||||||
|
|
||||||
var index = Collections.binarySearch(events, cutoutTimestamp)
|
var index = events.binarySearch(cutoutTimestamp)
|
||||||
if (index < 0) {
|
if (index < 0) {
|
||||||
index = -(index + 1) // Convert the negative index to insertion point
|
index = -(index + 1) // Convert the negative index to insertion point
|
||||||
}
|
}
|
||||||
|
@ -91,7 +91,7 @@ public final class CollectionsBackport {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static boolean eq(Object o1, Object o2) {
|
static boolean eq(Object o1, Object o2) {
|
||||||
return o1 == null ? o2 == null : o1.equals(o2);
|
return Objects.equals(o1, o2);
|
||||||
}
|
}
|
||||||
|
|
||||||
static class UnmodifiableNavigableSetBackport<E>
|
static class UnmodifiableNavigableSetBackport<E>
|
||||||
|
@ -214,7 +214,7 @@ public class ContactsHelper {
|
|||||||
|
|
||||||
Map<uID, Map<String, String>> databaseValue = accessContactsDatabase(context, projection, selection, selectionArgs, null);
|
Map<uID, Map<String, String>> databaseValue = accessContactsDatabase(context, projection, selection, selectionArgs, null);
|
||||||
|
|
||||||
if (databaseValue.size() == 0) {
|
if (databaseValue.isEmpty()) {
|
||||||
throw new ContactNotFoundException("Querying for contact with id " + contactID + " returned no results.");
|
throw new ContactNotFoundException("Querying for contact with id " + contactID + " returned no results.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@ import java.util.UUID
|
|||||||
import androidx.core.content.edit
|
import androidx.core.content.edit
|
||||||
|
|
||||||
object DeviceHelper {
|
object DeviceHelper {
|
||||||
const val ProtocolVersion = 8
|
const val PROTOCOL_VERSION = 8
|
||||||
|
|
||||||
const val KEY_DEVICE_NAME_PREFERENCE = "device_name_preference"
|
const val KEY_DEVICE_NAME_PREFERENCE = "device_name_preference"
|
||||||
private const val KEY_DEVICE_NAME_FETCHED_FROM_THE_INTERNET = "device_name_downloaded_preference"
|
private const val KEY_DEVICE_NAME_FETCHED_FROM_THE_INTERNET = "device_name_downloaded_preference"
|
||||||
@ -85,7 +85,7 @@ object DeviceHelper {
|
|||||||
|
|
||||||
// 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.
|
// 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.
|
||||||
val preferences = PreferenceManager.getDefaultSharedPreferences(context)
|
val preferences = PreferenceManager.getDefaultSharedPreferences(context)
|
||||||
preferences.edit().putBoolean(KEY_DEVICE_NAME_FETCHED_FROM_THE_INTERNET, true).apply()
|
preferences.edit { putBoolean(KEY_DEVICE_NAME_FETCHED_FROM_THE_INTERNET, true) }
|
||||||
|
|
||||||
BufferedReader(
|
BufferedReader(
|
||||||
InputStreamReader(connection.getInputStream(), StandardCharsets.UTF_16)
|
InputStreamReader(connection.getInputStream(), StandardCharsets.UTF_16)
|
||||||
@ -124,7 +124,7 @@ object DeviceHelper {
|
|||||||
fun setDeviceName(context: Context, name: String) {
|
fun setDeviceName(context: Context, name: String) {
|
||||||
val filteredName = filterName(name)
|
val filteredName = filterName(name)
|
||||||
val preferences = PreferenceManager.getDefaultSharedPreferences(context)
|
val preferences = PreferenceManager.getDefaultSharedPreferences(context)
|
||||||
preferences.edit().putString(KEY_DEVICE_NAME_PREFERENCE, filteredName).apply()
|
preferences.edit { putString(KEY_DEVICE_NAME_PREFERENCE, filteredName) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun initializeDeviceId(context: Context) {
|
fun initializeDeviceId(context: Context) {
|
||||||
@ -133,7 +133,6 @@ object DeviceHelper {
|
|||||||
if (DeviceInfo.isValidDeviceId(deviceId)) {
|
if (DeviceInfo.isValidDeviceId(deviceId)) {
|
||||||
return // We already have an ID
|
return // We already have an ID
|
||||||
}
|
}
|
||||||
@SuppressLint("HardwareIds")
|
|
||||||
val deviceName = UUID.randomUUID().toString().replace("-", "")
|
val deviceName = UUID.randomUUID().toString().replace("-", "")
|
||||||
preferences.edit { putString(KEY_DEVICE_ID_PREFERENCE, deviceName) }
|
preferences.edit { putString(KEY_DEVICE_ID_PREFERENCE, deviceName) }
|
||||||
}
|
}
|
||||||
@ -151,7 +150,7 @@ object DeviceHelper {
|
|||||||
SslHelper.certificate,
|
SslHelper.certificate,
|
||||||
getDeviceName(context),
|
getDeviceName(context),
|
||||||
deviceType,
|
deviceType,
|
||||||
ProtocolVersion,
|
PROTOCOL_VERSION,
|
||||||
PluginFactory.incomingCapabilities,
|
PluginFactory.incomingCapabilities,
|
||||||
PluginFactory.outgoingCapabilities
|
PluginFactory.outgoingCapabilities
|
||||||
)
|
)
|
||||||
|
@ -97,7 +97,7 @@ object FilesHelper {
|
|||||||
|
|
||||||
fun contentResolverExtract(): Triple<String?, Long, Long?> {
|
fun contentResolverExtract(): Triple<String?, Long, Long?> {
|
||||||
// Since we used Intent.CATEGORY_OPENABLE, these two columns are the only ones we are guaranteed to have: https://developer.android.com/reference/android/provider/OpenableColumns
|
// Since we used Intent.CATEGORY_OPENABLE, these two columns are the only ones we are guaranteed to have: https://developer.android.com/reference/android/provider/OpenableColumns
|
||||||
val proj = arrayOf(OpenableColumns.SIZE, OpenableColumns.DISPLAY_NAME,)
|
val proj = arrayOf(OpenableColumns.SIZE, OpenableColumns.DISPLAY_NAME)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
contentResolver.query(uri, proj, null, null, null).use { cursor ->
|
contentResolver.query(uri, proj, null, null, null).use { cursor ->
|
||||||
|
@ -11,7 +11,6 @@ import android.content.ContentUris
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.database.ContentObserver
|
import android.database.ContentObserver
|
||||||
import android.database.sqlite.SQLiteException
|
import android.database.sqlite.SQLiteException
|
||||||
import android.graphics.Bitmap
|
|
||||||
import android.media.MediaMetadataRetriever
|
import android.media.MediaMetadataRetriever
|
||||||
import android.media.ThumbnailUtils
|
import android.media.ThumbnailUtils
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
@ -23,6 +22,8 @@ import android.telephony.TelephonyManager
|
|||||||
import android.util.Log
|
import android.util.Log
|
||||||
import android.util.Pair
|
import android.util.Pair
|
||||||
import androidx.annotation.RequiresApi
|
import androidx.annotation.RequiresApi
|
||||||
|
import androidx.core.graphics.scale
|
||||||
|
import androidx.core.net.toUri
|
||||||
import com.google.android.mms.pdu_alt.MultimediaMessagePdu
|
import com.google.android.mms.pdu_alt.MultimediaMessagePdu
|
||||||
import com.google.android.mms.pdu_alt.PduPersister
|
import com.google.android.mms.pdu_alt.PduPersister
|
||||||
import com.google.android.mms.util_alt.PduCache
|
import com.google.android.mms.util_alt.PduCache
|
||||||
@ -37,13 +38,11 @@ import org.kde.kdeconnect.Helpers.TelephonyHelper.LocalPhoneNumber
|
|||||||
import org.kde.kdeconnect.Plugins.SMSPlugin.MimeType
|
import org.kde.kdeconnect.Plugins.SMSPlugin.MimeType
|
||||||
import org.kde.kdeconnect.Plugins.SMSPlugin.SmsMmsUtils
|
import org.kde.kdeconnect.Plugins.SMSPlugin.SmsMmsUtils
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.util.Arrays
|
|
||||||
import java.util.Objects
|
import java.util.Objects
|
||||||
import java.util.SortedMap
|
import java.util.SortedMap
|
||||||
import java.util.TreeMap
|
import java.util.TreeMap
|
||||||
import java.util.concurrent.locks.Lock
|
import java.util.concurrent.locks.Lock
|
||||||
import java.util.concurrent.locks.ReentrantLock
|
import java.util.concurrent.locks.ReentrantLock
|
||||||
import java.util.stream.Collectors
|
|
||||||
import kotlin.text.Charsets.UTF_8
|
import kotlin.text.Charsets.UTF_8
|
||||||
|
|
||||||
@SuppressLint("InlinedApi")
|
@SuppressLint("InlinedApi")
|
||||||
@ -52,7 +51,7 @@ object SMSHelper {
|
|||||||
private const val THUMBNAIL_WIDTH = 100
|
private const val THUMBNAIL_WIDTH = 100
|
||||||
|
|
||||||
// The constant Telephony.Mms.Part.CONTENT_URI was added in API 29
|
// The constant Telephony.Mms.Part.CONTENT_URI was added in API 29
|
||||||
val mMSPartUri : Uri = Uri.parse("content://mms/part/")
|
val mMSPartUri : Uri = "content://mms/part/".toUri()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the base address for all message conversations
|
* Get the base address for all message conversations
|
||||||
@ -67,14 +66,14 @@ object SMSHelper {
|
|||||||
if ("Samsung".equals(Build.MANUFACTURER, ignoreCase = true)) {
|
if ("Samsung".equals(Build.MANUFACTURER, ignoreCase = true)) {
|
||||||
Log.i("SMSHelper", "This appears to be a Samsung device. This may cause some features to not work properly.")
|
Log.i("SMSHelper", "This appears to be a Samsung device. This may cause some features to not work properly.")
|
||||||
}
|
}
|
||||||
return Uri.parse("content://mms-sms/conversations?simple=true")
|
return "content://mms-sms/conversations?simple=true".toUri()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getCompleteConversationsUri(): Uri {
|
private fun getCompleteConversationsUri(): Uri {
|
||||||
// This glorious - but completely undocumented - content URI gives us all messages, both MMS and SMS,
|
// This glorious - but completely undocumented - content URI gives us all messages, both MMS and SMS,
|
||||||
// in all conversations
|
// in all conversations
|
||||||
// See https://stackoverflow.com/a/36439630/3723163
|
// See https://stackoverflow.com/a/36439630/3723163
|
||||||
return Uri.parse("content://mms-sms/complete-conversations")
|
return "content://mms-sms/complete-conversations".toUri()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -651,12 +650,7 @@ object SMSHelper {
|
|||||||
)
|
)
|
||||||
val videoThumbnail = retriever.frameAtTime
|
val videoThumbnail = retriever.frameAtTime
|
||||||
val encodedThumbnail = SmsMmsUtils.bitMapToBase64(
|
val encodedThumbnail = SmsMmsUtils.bitMapToBase64(
|
||||||
Bitmap.createScaledBitmap(
|
videoThumbnail!!.scale(THUMBNAIL_WIDTH, THUMBNAIL_HEIGHT)
|
||||||
videoThumbnail!!,
|
|
||||||
THUMBNAIL_WIDTH,
|
|
||||||
THUMBNAIL_HEIGHT,
|
|
||||||
true
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
attachments.add(
|
attachments.add(
|
||||||
Attachment(
|
Attachment(
|
||||||
|
@ -24,7 +24,6 @@ import org.bouncycastle.cert.X509v3CertificateBuilder;
|
|||||||
import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder;
|
import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder;
|
||||||
import org.bouncycastle.operator.ContentSigner;
|
import org.bouncycastle.operator.ContentSigner;
|
||||||
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
|
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
|
||||||
import org.bouncycastle.util.Arrays;
|
|
||||||
import org.kde.kdeconnect.Helpers.DeviceHelper;
|
import org.kde.kdeconnect.Helpers.DeviceHelper;
|
||||||
import org.kde.kdeconnect.Helpers.RandomHelper;
|
import org.kde.kdeconnect.Helpers.RandomHelper;
|
||||||
import org.kde.kdeconnect.KdeConnect;
|
import org.kde.kdeconnect.KdeConnect;
|
||||||
|
@ -6,7 +6,6 @@
|
|||||||
package org.kde.kdeconnect.Helpers
|
package org.kde.kdeconnect.Helpers
|
||||||
|
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.provider.DocumentsContract
|
|
||||||
|
|
||||||
object StorageHelper {
|
object StorageHelper {
|
||||||
fun getDisplayName(treeUri: Uri): String {
|
fun getDisplayName(treeUri: Uri): String {
|
||||||
|
@ -13,6 +13,7 @@ import android.net.wifi.WifiManager
|
|||||||
import android.preference.PreferenceManager
|
import android.preference.PreferenceManager
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
|
import androidx.core.content.edit
|
||||||
|
|
||||||
class TrustedNetworkHelper(private val context: Context) {
|
class TrustedNetworkHelper(private val context: Context) {
|
||||||
|
|
||||||
@ -22,19 +23,19 @@ class TrustedNetworkHelper(private val context: Context) {
|
|||||||
return serializedNetworks.split(NETWORK_SSID_DELIMITER, "#_#" /* TODO remove old delimiter in 2025 */).filter { it.isNotEmpty() }
|
return serializedNetworks.split(NETWORK_SSID_DELIMITER, "#_#" /* TODO remove old delimiter in 2025 */).filter { it.isNotEmpty() }
|
||||||
}
|
}
|
||||||
set(value) {
|
set(value) {
|
||||||
PreferenceManager.getDefaultSharedPreferences(context)
|
PreferenceManager.getDefaultSharedPreferences(context).edit {
|
||||||
.edit()
|
putString(
|
||||||
.putString(KEY_CUSTOM_TRUSTED_NETWORKS, value.joinToString(NETWORK_SSID_DELIMITER))
|
KEY_CUSTOM_TRUSTED_NETWORKS,
|
||||||
.apply()
|
value.joinToString(NETWORK_SSID_DELIMITER)
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var allNetworksAllowed: Boolean
|
var allNetworksAllowed: Boolean
|
||||||
get() = !hasPermissions || PreferenceManager.getDefaultSharedPreferences(context).getBoolean(KEY_CUSTOM_TRUST_ALL_NETWORKS, true)
|
get() = !hasPermissions || PreferenceManager.getDefaultSharedPreferences(context).getBoolean(KEY_CUSTOM_TRUST_ALL_NETWORKS, true)
|
||||||
set(value) = PreferenceManager
|
set(value) = PreferenceManager.getDefaultSharedPreferences(context).edit {
|
||||||
.getDefaultSharedPreferences(context)
|
putBoolean(KEY_CUSTOM_TRUST_ALL_NETWORKS, value)
|
||||||
.edit()
|
}
|
||||||
.putBoolean(KEY_CUSTOM_TRUST_ALL_NETWORKS, value)
|
|
||||||
.apply()
|
|
||||||
|
|
||||||
val hasPermissions: Boolean
|
val hasPermissions: Boolean
|
||||||
get() = ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED
|
get() = ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED
|
||||||
|
@ -25,6 +25,7 @@ import java.security.cert.CertificateException
|
|||||||
import java.security.cert.X509Certificate
|
import java.security.cert.X509Certificate
|
||||||
import java.util.Date
|
import java.util.Date
|
||||||
import java.util.concurrent.ConcurrentHashMap
|
import java.util.concurrent.ConcurrentHashMap
|
||||||
|
import androidx.core.content.edit
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This class holds all the active devices and makes them accessible from every other class.
|
* This class holds all the active devices and makes them accessible from every other class.
|
||||||
@ -116,7 +117,7 @@ class KdeConnect : Application() {
|
|||||||
"KdeConnect",
|
"KdeConnect",
|
||||||
"Couldn't load the certificate for a remembered device. Removing from trusted list.", e
|
"Couldn't load the certificate for a remembered device. Removing from trusted list.", e
|
||||||
)
|
)
|
||||||
preferences.edit().remove(it).apply()
|
preferences.edit { remove(it) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -127,7 +128,7 @@ class KdeConnect : Application() {
|
|||||||
trustedDevices.filter { preferences.getBoolean(it, false) }
|
trustedDevices.filter { preferences.getBoolean(it, false) }
|
||||||
.forEach {
|
.forEach {
|
||||||
Log.d("KdeConnect", "Removing devices: $it")
|
Log.d("KdeConnect", "Removing devices: $it")
|
||||||
preferences.edit().remove(it).apply()
|
preferences.edit { remove(it) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,9 +11,7 @@ import org.json.JSONObject
|
|||||||
import java.io.ByteArrayInputStream
|
import java.io.ByteArrayInputStream
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
import java.lang.RuntimeException
|
|
||||||
import java.net.Socket
|
import java.net.Socket
|
||||||
import kotlin.concurrent.Volatile
|
|
||||||
|
|
||||||
class NetworkPacket private constructor(
|
class NetworkPacket private constructor(
|
||||||
val type: String,
|
val type: String,
|
||||||
|
@ -25,8 +25,6 @@ import org.kde.kdeconnect.Plugins.Plugin;
|
|||||||
import org.kde.kdeconnect.Plugins.PluginFactory;
|
import org.kde.kdeconnect.Plugins.PluginFactory;
|
||||||
import org.kde.kdeconnect_tp.R;
|
import org.kde.kdeconnect_tp.R;
|
||||||
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
@PluginFactory.LoadablePlugin
|
@PluginFactory.LoadablePlugin
|
||||||
public class BigscreenPlugin extends Plugin {
|
public class BigscreenPlugin extends Plugin {
|
||||||
|
|
||||||
|
@ -25,8 +25,6 @@ import org.kde.kdeconnect.Plugins.Plugin;
|
|||||||
import org.kde.kdeconnect.Plugins.PluginFactory;
|
import org.kde.kdeconnect.Plugins.PluginFactory;
|
||||||
import org.kde.kdeconnect_tp.R;
|
import org.kde.kdeconnect_tp.R;
|
||||||
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
@PluginFactory.LoadablePlugin
|
@PluginFactory.LoadablePlugin
|
||||||
public class ClipboardPlugin extends Plugin {
|
public class ClipboardPlugin extends Plugin {
|
||||||
|
|
||||||
|
@ -37,7 +37,6 @@ import org.kde.kdeconnect.UserInterface.PluginSettingsFragment;
|
|||||||
import org.kde.kdeconnect_tp.R;
|
import org.kde.kdeconnect_tp.R;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
@PluginFactory.LoadablePlugin
|
@PluginFactory.LoadablePlugin
|
||||||
public class FindMyPhonePlugin extends Plugin {
|
public class FindMyPhonePlugin extends Plugin {
|
||||||
|
@ -19,8 +19,6 @@ import org.kde.kdeconnect.Plugins.PluginFactory;
|
|||||||
import org.kde.kdeconnect.UserInterface.PluginSettingsFragment;
|
import org.kde.kdeconnect.UserInterface.PluginSettingsFragment;
|
||||||
import org.kde.kdeconnect_tp.R;
|
import org.kde.kdeconnect_tp.R;
|
||||||
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
@PluginFactory.LoadablePlugin
|
@PluginFactory.LoadablePlugin
|
||||||
public class MousePadPlugin extends Plugin {
|
public class MousePadPlugin extends Plugin {
|
||||||
|
|
||||||
|
@ -157,9 +157,6 @@ public class PointerAccelerationProfileFactory {
|
|||||||
|
|
||||||
public static PointerAccelerationProfile getProfileWithName(String name) {
|
public static PointerAccelerationProfile getProfileWithName(String name) {
|
||||||
switch (name) {
|
switch (name) {
|
||||||
case "noacceleration":
|
|
||||||
default:
|
|
||||||
return new DefaultProfile();
|
|
||||||
case "weaker":
|
case "weaker":
|
||||||
return new PolynomialProfile(0.25f);
|
return new PolynomialProfile(0.25f);
|
||||||
case "weak":
|
case "weak":
|
||||||
@ -170,6 +167,9 @@ public class PointerAccelerationProfileFactory {
|
|||||||
return new PolynomialProfile(1.5f);
|
return new PolynomialProfile(1.5f);
|
||||||
case "stronger":
|
case "stronger":
|
||||||
return new PolynomialProfile(2.0f);
|
return new PolynomialProfile(2.0f);
|
||||||
|
case "noacceleration":
|
||||||
|
default:
|
||||||
|
return new DefaultProfile();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,6 +29,7 @@ import java.net.URL
|
|||||||
import java.net.URLDecoder
|
import java.net.URLDecoder
|
||||||
import java.security.MessageDigest
|
import java.security.MessageDigest
|
||||||
import java.util.concurrent.CopyOnWriteArrayList
|
import java.util.concurrent.CopyOnWriteArrayList
|
||||||
|
import androidx.core.net.toUri
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles the cache for album art
|
* Handles the cache for album art
|
||||||
@ -130,7 +131,7 @@ internal object AlbumArtCache {
|
|||||||
if (albumUrl.isNullOrEmpty()) {
|
if (albumUrl.isNullOrEmpty()) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
val url = Uri.parse(albumUrl)
|
val url = albumUrl.toUri()
|
||||||
|
|
||||||
//We currently only support http(s), file, and kdeconnect urls
|
//We currently only support http(s), file, and kdeconnect urls
|
||||||
if (url.scheme !in ALLOWED_SCHEMES) {
|
if (url.scheme !in ALLOWED_SCHEMES) {
|
||||||
@ -221,7 +222,7 @@ internal object AlbumArtCache {
|
|||||||
* Does the actual fetching and makes sure only not too many fetches are running at the same time
|
* Does the actual fetching and makes sure only not too many fetches are running at the same time
|
||||||
*/
|
*/
|
||||||
private fun initiateFetch() {
|
private fun initiateFetch() {
|
||||||
var url : Uri;
|
var url : Uri
|
||||||
synchronized(fetchUrlList) {
|
synchronized(fetchUrlList) {
|
||||||
if (numFetching >= 2 || fetchUrlList.isEmpty()) return
|
if (numFetching >= 2 || fetchUrlList.isEmpty()) return
|
||||||
//Fetch the last-requested url first, it will probably be needed first
|
//Fetch the last-requested url first, it will probably be needed first
|
||||||
@ -283,7 +284,7 @@ internal object AlbumArtCache {
|
|||||||
payload.close()
|
payload.close()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
val url = Uri.parse(albumUrl)
|
val url = albumUrl.toUri()
|
||||||
if (url.scheme !in REMOTE_FETCH_SCHEMES) {
|
if (url.scheme !in REMOTE_FETCH_SCHEMES) {
|
||||||
//Shouldn't happen (checked on receival of the url), but just to be sure
|
//Shouldn't happen (checked on receival of the url), but just to be sure
|
||||||
Log.e("KDE/Mpris/AlbumArtCache", "Got invalid art url with payload: $albumUrl")
|
Log.e("KDE/Mpris/AlbumArtCache", "Got invalid art url with payload: $albumUrl")
|
||||||
|
@ -34,6 +34,7 @@ import org.kde.kdeconnect_tp.databinding.MprisNowPlayingBinding
|
|||||||
import java.net.MalformedURLException
|
import java.net.MalformedURLException
|
||||||
import kotlin.time.Duration
|
import kotlin.time.Duration
|
||||||
import kotlin.time.Duration.Companion.milliseconds
|
import kotlin.time.Duration.Companion.milliseconds
|
||||||
|
import androidx.core.net.toUri
|
||||||
|
|
||||||
private typealias MprisPlayerCallback = (MprisPlayer) -> Unit
|
private typealias MprisPlayerCallback = (MprisPlayer) -> Unit
|
||||||
|
|
||||||
@ -370,7 +371,7 @@ class MprisNowPlayingFragment : Fragment(), VolumeKeyListener {
|
|||||||
if (targetPlayer != null && item.itemId == MENU_OPEN_URL) {
|
if (targetPlayer != null && item.itemId == MENU_OPEN_URL) {
|
||||||
try {
|
try {
|
||||||
val url = VideoUrlsHelper.formatUriWithSeek(targetPlayer.url, targetPlayer.position).toString()
|
val url = VideoUrlsHelper.formatUriWithSeek(targetPlayer.url, targetPlayer.position).toString()
|
||||||
val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse(url))
|
val browserIntent = Intent(Intent.ACTION_VIEW, url.toUri())
|
||||||
startActivity(browserIntent)
|
startActivity(browserIntent)
|
||||||
targetPlayer.sendPause()
|
targetPlayer.sendPause()
|
||||||
return true
|
return true
|
||||||
|
@ -33,6 +33,7 @@ import org.kde.kdeconnect.UserInterface.PluginSettingsFragment
|
|||||||
import org.kde.kdeconnect_tp.R
|
import org.kde.kdeconnect_tp.R
|
||||||
import java.net.MalformedURLException
|
import java.net.MalformedURLException
|
||||||
import java.util.concurrent.ConcurrentHashMap
|
import java.util.concurrent.ConcurrentHashMap
|
||||||
|
import androidx.core.net.toUri
|
||||||
|
|
||||||
@LoadablePlugin
|
@LoadablePlugin
|
||||||
class MprisPlugin : Plugin() {
|
class MprisPlugin : Plugin() {
|
||||||
@ -273,7 +274,7 @@ class MprisPlugin : Plugin() {
|
|||||||
playerStatus.isGoPreviousAllowed = np.getBoolean("canGoPrevious", playerStatus.isGoPreviousAllowed)
|
playerStatus.isGoPreviousAllowed = np.getBoolean("canGoPrevious", playerStatus.isGoPreviousAllowed)
|
||||||
playerStatus.seekAllowed = np.getBoolean("canSeek", playerStatus.seekAllowed)
|
playerStatus.seekAllowed = np.getBoolean("canSeek", playerStatus.seekAllowed)
|
||||||
val newAlbumArtUrlString = np.getString("albumArtUrl", playerStatus.albumArtUrl)
|
val newAlbumArtUrlString = np.getString("albumArtUrl", playerStatus.albumArtUrl)
|
||||||
val newAlbumArtUrl = Uri.parse(newAlbumArtUrlString)
|
val newAlbumArtUrl = newAlbumArtUrlString.toUri()
|
||||||
if (newAlbumArtUrl.scheme in AlbumArtCache.ALLOWED_SCHEMES) {
|
if (newAlbumArtUrl.scheme in AlbumArtCache.ALLOWED_SCHEMES) {
|
||||||
playerStatus.albumArtUrl = newAlbumArtUrl.toString()
|
playerStatus.albumArtUrl = newAlbumArtUrl.toString()
|
||||||
} else {
|
} else {
|
||||||
@ -334,7 +335,7 @@ class MprisPlugin : Plugin() {
|
|||||||
) {
|
) {
|
||||||
try {
|
try {
|
||||||
val url = VideoUrlsHelper.formatUriWithSeek(playerStatus.url, playerStatus.position).toString()
|
val url = VideoUrlsHelper.formatUriWithSeek(playerStatus.url, playerStatus.position).toString()
|
||||||
val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse(url))
|
val browserIntent = Intent(Intent.ACTION_VIEW, url.toUri())
|
||||||
val pendingIntent = PendingIntent.getActivity(context, 0, browserIntent, PendingIntent.FLAG_IMMUTABLE)
|
val pendingIntent = PendingIntent.getActivity(context, 0, browserIntent, PendingIntent.FLAG_IMMUTABLE)
|
||||||
|
|
||||||
val notificationManager = ContextCompat.getSystemService(context, NotificationManager::class.java)
|
val notificationManager = ContextCompat.getSystemService(context, NotificationManager::class.java)
|
||||||
@ -350,7 +351,7 @@ class MprisPlugin : Plugin() {
|
|||||||
builder.build()
|
builder.build()
|
||||||
)
|
)
|
||||||
} catch (e: MalformedURLException) {
|
} catch (e: MalformedURLException) {
|
||||||
e.printStackTrace();
|
e.printStackTrace()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,6 @@ import android.util.Log
|
|||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.core.app.NotificationCompat
|
import androidx.core.app.NotificationCompat
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.core.content.ContextCompat.getSystemService
|
|
||||||
import androidx.core.content.getSystemService
|
import androidx.core.content.getSystemService
|
||||||
import org.kde.kdeconnect.Helpers.NotificationHelper
|
import org.kde.kdeconnect.Helpers.NotificationHelper
|
||||||
import org.kde.kdeconnect.NetworkPacket
|
import org.kde.kdeconnect.NetworkPacket
|
||||||
|
@ -24,8 +24,6 @@ import org.kde.kdeconnect.Plugins.Plugin;
|
|||||||
import org.kde.kdeconnect.Plugins.PluginFactory;
|
import org.kde.kdeconnect.Plugins.PluginFactory;
|
||||||
import org.kde.kdeconnect_tp.R;
|
import org.kde.kdeconnect_tp.R;
|
||||||
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
@PluginFactory.LoadablePlugin
|
@PluginFactory.LoadablePlugin
|
||||||
public class PresenterPlugin extends Plugin {
|
public class PresenterPlugin extends Plugin {
|
||||||
|
|
||||||
|
@ -29,7 +29,6 @@ import org.kde.kdeconnect.UserInterface.MainActivity;
|
|||||||
import org.kde.kdeconnect_tp.R;
|
import org.kde.kdeconnect_tp.R;
|
||||||
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
@PluginFactory.LoadablePlugin
|
@PluginFactory.LoadablePlugin
|
||||||
public class ReceiveNotificationsPlugin extends Plugin {
|
public class ReceiveNotificationsPlugin extends Plugin {
|
||||||
|
@ -67,7 +67,7 @@ public class RemoteKeyboardPlugin extends Plugin implements SharedPreferences.On
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isConnected() {
|
public static boolean isConnected() {
|
||||||
return instances.size() > 0;
|
return !instances.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final SparseIntArray specialKeyMap = new SparseIntArray();
|
private static final SparseIntArray specialKeyMap = new SparseIntArray();
|
||||||
@ -135,7 +135,7 @@ public class RemoteKeyboardPlugin extends Plugin implements SharedPreferences.On
|
|||||||
try {
|
try {
|
||||||
if (instances.contains(this)) {
|
if (instances.contains(this)) {
|
||||||
instances.remove(this);
|
instances.remove(this);
|
||||||
if (instances.size() < 1 && RemoteKeyboardService.instance != null)
|
if (instances.isEmpty() && RemoteKeyboardService.instance != null)
|
||||||
RemoteKeyboardService.instance.handler.post(() -> RemoteKeyboardService.instance.updateInputView());
|
RemoteKeyboardService.instance.handler.post(() -> RemoteKeyboardService.instance.updateInputView());
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
@ -348,7 +348,7 @@ public class RemoteKeyboardPlugin extends Plugin implements SharedPreferences.On
|
|||||||
public enum MousePadPacketType {
|
public enum MousePadPacketType {
|
||||||
Keyboard,
|
Keyboard,
|
||||||
Mouse,
|
Mouse,
|
||||||
};
|
}
|
||||||
|
|
||||||
public static MousePadPacketType getMousePadPacketType(NetworkPacket np) {
|
public static MousePadPacketType getMousePadPacketType(NetworkPacket np) {
|
||||||
if (np.has("key") || np.has("specialKey")) {
|
if (np.has("key") || np.has("specialKey")) {
|
||||||
|
@ -165,7 +165,7 @@ public class RemoteKeyboardService
|
|||||||
intent.putExtra(MainActivity.FLAG_FORCE_OVERVIEW, true);
|
intent.putExtra(MainActivity.FLAG_FORCE_OVERVIEW, true);
|
||||||
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||||
startActivity(intent);
|
startActivity(intent);
|
||||||
if (instances.size() < 1)
|
if (instances.isEmpty())
|
||||||
Toast.makeText(this, R.string.remotekeyboard_not_connected, Toast.LENGTH_SHORT).show();
|
Toast.makeText(this, R.string.remotekeyboard_not_connected, Toast.LENGTH_SHORT).show();
|
||||||
else // instances.size() > 1
|
else // instances.size() > 1
|
||||||
Toast.makeText(this, R.string.remotekeyboard_multiple_connections, Toast.LENGTH_SHORT).show();
|
Toast.makeText(this, R.string.remotekeyboard_multiple_connections, Toast.LENGTH_SHORT).show();
|
||||||
|
@ -130,7 +130,7 @@ public class RunCommandActivity extends BaseActivity<ActivityRunCommandBinding>
|
|||||||
public boolean onContextItemSelected(MenuItem item) {
|
public boolean onContextItemSelected(MenuItem item) {
|
||||||
AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
|
AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
|
||||||
if (item.getItemId() == R.id.copy_url_to_clipboard) {
|
if (item.getItemId() == R.id.copy_url_to_clipboard) {
|
||||||
CommandEntry entry = (CommandEntry) commandItems.get(info.position);
|
CommandEntry entry = commandItems.get(info.position);
|
||||||
String url = "kdeconnect://runcommand/" + deviceId + "/" + entry.getKey();
|
String url = "kdeconnect://runcommand/" + deviceId + "/" + entry.getKey();
|
||||||
ClipboardManager cm = ContextCompat.getSystemService(this, ClipboardManager.class);
|
ClipboardManager cm = ContextCompat.getSystemService(this, ClipboardManager.class);
|
||||||
cm.setText(url);
|
cm.setText(url);
|
||||||
|
@ -34,7 +34,6 @@ import org.kde.kdeconnect_tp.R;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
@PluginFactory.LoadablePlugin
|
@PluginFactory.LoadablePlugin
|
||||||
public class RunCommandPlugin extends Plugin {
|
public class RunCommandPlugin extends Plugin {
|
||||||
|
@ -18,12 +18,12 @@ import android.widget.ArrayAdapter
|
|||||||
import android.widget.ImageView
|
import android.widget.ImageView
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
import androidx.core.content.edit
|
||||||
import org.kde.kdeconnect.Device
|
import org.kde.kdeconnect.Device
|
||||||
import org.kde.kdeconnect.KdeConnect
|
import org.kde.kdeconnect.KdeConnect
|
||||||
import org.kde.kdeconnect_tp.R
|
import org.kde.kdeconnect_tp.R
|
||||||
import org.kde.kdeconnect_tp.databinding.WidgetRemoteCommandPluginDialogBinding
|
import org.kde.kdeconnect_tp.databinding.WidgetRemoteCommandPluginDialogBinding
|
||||||
import java.util.stream.Collectors
|
import java.util.stream.Collectors
|
||||||
import kotlin.streams.toList
|
|
||||||
|
|
||||||
class RunCommandWidgetConfigActivity : AppCompatActivity() {
|
class RunCommandWidgetConfigActivity : AppCompatActivity() {
|
||||||
|
|
||||||
@ -45,7 +45,7 @@ class RunCommandWidgetConfigActivity : AppCompatActivity() {
|
|||||||
val binding = WidgetRemoteCommandPluginDialogBinding.inflate(layoutInflater)
|
val binding = WidgetRemoteCommandPluginDialogBinding.inflate(layoutInflater)
|
||||||
setContentView(binding.root)
|
setContentView(binding.root)
|
||||||
|
|
||||||
val pairedDevices = KdeConnect.getInstance().devices.values.stream().filter(Device::isPaired).collect(Collectors.toList());
|
val pairedDevices = KdeConnect.getInstance().devices.values.stream().filter(Device::isPaired).collect(Collectors.toList())
|
||||||
|
|
||||||
binding.runCommandsDeviceList.adapter = object : ArrayAdapter<Device>(this, 0, pairedDevices) {
|
binding.runCommandsDeviceList.adapter = object : ArrayAdapter<Device>(this, 0, pairedDevices) {
|
||||||
override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
|
override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
|
||||||
@ -76,9 +76,9 @@ private const val PREFS_NAME = "org.kde.kdeconnect_tp.WidgetProvider"
|
|||||||
private const val PREF_PREFIX_KEY = "appwidget_"
|
private const val PREF_PREFIX_KEY = "appwidget_"
|
||||||
|
|
||||||
internal fun saveWidgetDeviceIdPref(context: Context, appWidgetId: Int, deviceName: String) {
|
internal fun saveWidgetDeviceIdPref(context: Context, appWidgetId: Int, deviceName: String) {
|
||||||
val prefs = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE).edit()
|
context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE).edit {
|
||||||
prefs.putString(PREF_PREFIX_KEY + appWidgetId, deviceName)
|
putString(PREF_PREFIX_KEY + appWidgetId, deviceName)
|
||||||
prefs.apply()
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun loadWidgetDeviceIdPref(context: Context, appWidgetId: Int): String? {
|
internal fun loadWidgetDeviceIdPref(context: Context, appWidgetId: Int): String? {
|
||||||
@ -87,7 +87,7 @@ internal fun loadWidgetDeviceIdPref(context: Context, appWidgetId: Int): String?
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal fun deleteWidgetDeviceIdPref(context: Context, appWidgetId: Int) {
|
internal fun deleteWidgetDeviceIdPref(context: Context, appWidgetId: Int) {
|
||||||
val prefs = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE).edit()
|
context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE).edit {
|
||||||
prefs.remove(PREF_PREFIX_KEY + appWidgetId)
|
remove(PREF_PREFIX_KEY + appWidgetId)
|
||||||
prefs.apply()
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,7 @@ import org.kde.kdeconnect.Device
|
|||||||
import org.kde.kdeconnect.KdeConnect
|
import org.kde.kdeconnect.KdeConnect
|
||||||
import org.kde.kdeconnect_tp.BuildConfig
|
import org.kde.kdeconnect_tp.BuildConfig
|
||||||
import org.kde.kdeconnect_tp.R
|
import org.kde.kdeconnect_tp.R
|
||||||
|
import androidx.core.net.toUri
|
||||||
|
|
||||||
const val RUN_COMMAND_ACTION = "RUN_COMMAND_ACTION"
|
const val RUN_COMMAND_ACTION = "RUN_COMMAND_ACTION"
|
||||||
const val TARGET_COMMAND = "TARGET_COMMAND"
|
const val TARGET_COMMAND = "TARGET_COMMAND"
|
||||||
@ -65,10 +66,10 @@ class RunCommandWidgetProvider : AppWidgetProvider() {
|
|||||||
Log.e("RunCommandWidget", "Error running command", ex)
|
Log.e("RunCommandWidget", "Error running command", ex)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Log.w("RunCommandWidget", "Device not available or runcommand plugin disabled");
|
Log.w("RunCommandWidget", "Device not available or runcommand plugin disabled")
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
super.onReceive(context, intent);
|
super.onReceive(context, intent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -114,7 +115,7 @@ internal fun updateAppWidget(
|
|||||||
val views = RemoteViews(BuildConfig.APPLICATION_ID, R.layout.widget_remotecommandplugin)
|
val views = RemoteViews(BuildConfig.APPLICATION_ID, R.layout.widget_remotecommandplugin)
|
||||||
assignTitleIntent(context, appWidgetId, views)
|
assignTitleIntent(context, appWidgetId, views)
|
||||||
|
|
||||||
Log.d("WidgetProvider", "updateAppWidget device: " + if (device == null) "null" else device.name)
|
Log.d("WidgetProvider", "updateAppWidget device: " + (device?.name ?: "null"))
|
||||||
|
|
||||||
// Android should automatically toggle between the command list and the error text
|
// Android should automatically toggle between the command list and the error text
|
||||||
views.setEmptyView(R.id.widget_command_list, R.id.widget_error_text)
|
views.setEmptyView(R.id.widget_command_list, R.id.widget_error_text)
|
||||||
@ -174,7 +175,7 @@ private fun assignTitleIntent(context: Context, appWidgetId: Int, views: RemoteV
|
|||||||
private fun assignListAdapter(context: Context, appWidgetId: Int, views: RemoteViews) {
|
private fun assignListAdapter(context: Context, appWidgetId: Int, views: RemoteViews) {
|
||||||
val dataProviderIntent = Intent(context, CommandsRemoteViewsService::class.java)
|
val dataProviderIntent = Intent(context, CommandsRemoteViewsService::class.java)
|
||||||
dataProviderIntent.putExtra(EXTRA_APPWIDGET_ID, appWidgetId)
|
dataProviderIntent.putExtra(EXTRA_APPWIDGET_ID, appWidgetId)
|
||||||
dataProviderIntent.data = Uri.parse(dataProviderIntent.toUri(Intent.URI_INTENT_SCHEME))
|
dataProviderIntent.data = dataProviderIntent.toUri(Intent.URI_INTENT_SCHEME).toUri()
|
||||||
views.setRemoteAdapter(R.id.widget_command_list, dataProviderIntent)
|
views.setRemoteAdapter(R.id.widget_command_list, dataProviderIntent)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -181,7 +181,7 @@ class SMSPlugin : Plugin() {
|
|||||||
@Deprecated("")
|
@Deprecated("")
|
||||||
private fun smsBroadcastReceivedDeprecated(messages: MutableList<SmsMessage>) {
|
private fun smsBroadcastReceivedDeprecated(messages: MutableList<SmsMessage>) {
|
||||||
if (BuildConfig.DEBUG) {
|
if (BuildConfig.DEBUG) {
|
||||||
if (messages.size <= 0) {
|
if (messages.isEmpty()) {
|
||||||
throw AssertionError("This method requires at least one message")
|
throw AssertionError("This method requires at least one message")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -224,11 +224,11 @@ class SMSPlugin : Plugin() {
|
|||||||
get() = R.string.telepathy_permission_explanation
|
get() = R.string.telepathy_permission_explanation
|
||||||
|
|
||||||
override fun onCreate(): Boolean {
|
override fun onCreate(): Boolean {
|
||||||
val filter: IntentFilter = IntentFilter(Telephony.Sms.Intents.SMS_RECEIVED_ACTION)
|
val filter = IntentFilter(Telephony.Sms.Intents.SMS_RECEIVED_ACTION)
|
||||||
filter.priority = 500
|
filter.priority = 500
|
||||||
context.registerReceiver(receiver, filter)
|
context.registerReceiver(receiver, filter)
|
||||||
|
|
||||||
val refreshFilter: IntentFilter = IntentFilter(Transaction.REFRESH)
|
val refreshFilter = IntentFilter(Transaction.REFRESH)
|
||||||
refreshFilter.priority = 500
|
refreshFilter.priority = 500
|
||||||
context.registerReceiver(messagesUpdateReceiver, refreshFilter, ContextCompat.RECEIVER_EXPORTED)
|
context.registerReceiver(messagesUpdateReceiver, refreshFilter, ContextCompat.RECEIVER_EXPORTED)
|
||||||
|
|
||||||
@ -269,13 +269,11 @@ class SMSPlugin : Plugin() {
|
|||||||
val subID = np.getLong("subID", -1)
|
val subID = np.getLong("subID", -1)
|
||||||
|
|
||||||
val jsonAddressList = np.getJSONArray("addresses")
|
val jsonAddressList = np.getJSONArray("addresses")
|
||||||
val addressList: List<SMSHelper.Address>
|
val addressList = if (jsonAddressList == null) {
|
||||||
if (jsonAddressList == null) {
|
|
||||||
// If jsonAddressList is null, then the SMS_REQUEST packet is most probably from the older version of the desktop app.
|
// If jsonAddressList is null, then the SMS_REQUEST packet is most probably from the older version of the desktop app.
|
||||||
addressList = listOf(SMSHelper.Address(context, np.getString("phoneNumber")))
|
listOf(SMSHelper.Address(context, np.getString("phoneNumber")))
|
||||||
}
|
} else {
|
||||||
else {
|
jsonArrayToAddressList(context, jsonAddressList)
|
||||||
addressList = jsonArrayToAddressList(context, jsonAddressList)
|
|
||||||
}
|
}
|
||||||
val attachedFiles: List<SMSHelper.Attachment> = jsonArrayToAttachmentsList(np.getJSONArray("attachments"))
|
val attachedFiles: List<SMSHelper.Attachment> = jsonArrayToAttachmentsList(np.getJSONArray("attachments"))
|
||||||
|
|
||||||
@ -350,11 +348,10 @@ class SMSPlugin : Plugin() {
|
|||||||
numberToGet = null
|
numberToGet = null
|
||||||
}
|
}
|
||||||
|
|
||||||
val conversation: List<SMSHelper.Message>
|
val conversation = if (rangeStartTimestamp < 0) {
|
||||||
if (rangeStartTimestamp < 0) {
|
getMessagesInThread(this.context, threadID, numberToGet)
|
||||||
conversation = getMessagesInThread(this.context, threadID, numberToGet)
|
|
||||||
} else {
|
} else {
|
||||||
conversation = getMessagesInRange(this.context, threadID, rangeStartTimestamp, numberToGet, true)
|
getMessagesInRange(this.context, threadID, rangeStartTimestamp, numberToGet, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
val reply: NetworkPacket = constructBulkMessagePacket(conversation)
|
val reply: NetworkPacket = constructBulkMessagePacket(conversation)
|
||||||
|
@ -11,10 +11,10 @@ import android.content.ContentResolver
|
|||||||
import android.content.SharedPreferences
|
import android.content.SharedPreferences
|
||||||
import android.content.SharedPreferences.OnSharedPreferenceChangeListener
|
import android.content.SharedPreferences.OnSharedPreferenceChangeListener
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Build
|
|
||||||
import android.os.Environment
|
import android.os.Environment
|
||||||
import android.os.storage.StorageManager
|
import android.os.storage.StorageManager
|
||||||
import android.provider.Settings
|
import android.provider.Settings
|
||||||
|
import androidx.core.net.toUri
|
||||||
import org.json.JSONException
|
import org.json.JSONException
|
||||||
import org.json.JSONObject
|
import org.json.JSONObject
|
||||||
import org.kde.kdeconnect.Helpers.NetworkHelper.localIpAddress
|
import org.kde.kdeconnect.Helpers.NetworkHelper.localIpAddress
|
||||||
@ -44,7 +44,7 @@ class SftpPlugin : Plugin(), OnSharedPreferenceChangeListener {
|
|||||||
return if (SimpleSftpServer.SUPPORTS_NATIVEFS) {
|
return if (SimpleSftpServer.SUPPORTS_NATIVEFS) {
|
||||||
Environment.isExternalStorageManager()
|
Environment.isExternalStorageManager()
|
||||||
} else {
|
} else {
|
||||||
SftpSettingsFragment.getStorageInfoList(context, this).size != 0
|
SftpSettingsFragment.getStorageInfoList(context, this).isNotEmpty()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -101,7 +101,7 @@ class SftpPlugin : Plugin(), OnSharedPreferenceChangeListener {
|
|||||||
} else {
|
} else {
|
||||||
val storageInfoList = SftpSettingsFragment.getStorageInfoList(context, this)
|
val storageInfoList = SftpSettingsFragment.getStorageInfoList(context, this)
|
||||||
storageInfoList.sortBy { it.uri }
|
storageInfoList.sortBy { it.uri }
|
||||||
if (storageInfoList.size <= 0) {
|
if (storageInfoList.isEmpty()) {
|
||||||
device.sendPacket(NetworkPacket(PACKET_TYPE_SFTP).apply {
|
device.sendPacket(NetworkPacket(PACKET_TYPE_SFTP).apply {
|
||||||
this["errorMessage"] = context.getString(R.string.sftp_no_storage_locations_configured)
|
this["errorMessage"] = context.getString(R.string.sftp_no_storage_locations_configured)
|
||||||
})
|
})
|
||||||
@ -127,7 +127,7 @@ class SftpPlugin : Plugin(), OnSharedPreferenceChangeListener {
|
|||||||
this["password"] = server.regeneratePassword()
|
this["password"] = server.regeneratePassword()
|
||||||
// Kept for compatibility, in case "multiPaths" is not possible or the other end does not support it
|
// Kept for compatibility, in case "multiPaths" is not possible or the other end does not support it
|
||||||
this["path"] = if (paths.size == 1) paths[0] else "/"
|
this["path"] = if (paths.size == 1) paths[0] else "/"
|
||||||
if (paths.size > 0) {
|
if (paths.isNotEmpty()) {
|
||||||
this["multiPaths"] = paths
|
this["multiPaths"] = paths
|
||||||
this["pathNames"] = pathNames
|
this["pathNames"] = pathNames
|
||||||
}
|
}
|
||||||
@ -240,7 +240,7 @@ class SftpPlugin : Plugin(), OnSharedPreferenceChangeListener {
|
|||||||
@Throws(JSONException::class)
|
@Throws(JSONException::class)
|
||||||
fun fromJSON(jsonObject: JSONObject): StorageInfo { // TODO: Use Result after migrate callee to Kotlin
|
fun fromJSON(jsonObject: JSONObject): StorageInfo { // TODO: Use Result after migrate callee to Kotlin
|
||||||
val displayName = jsonObject.getString(KEY_DISPLAY_NAME)
|
val displayName = jsonObject.getString(KEY_DISPLAY_NAME)
|
||||||
val uri = Uri.parse(jsonObject.getString(KEY_URI))
|
val uri = jsonObject.getString(KEY_URI).toUri()
|
||||||
|
|
||||||
return StorageInfo(displayName, uri)
|
return StorageInfo(displayName, uri)
|
||||||
}
|
}
|
||||||
|
@ -48,6 +48,7 @@ import java.security.KeyPair
|
|||||||
import java.security.MessageDigest
|
import java.security.MessageDigest
|
||||||
import java.security.NoSuchAlgorithmException
|
import java.security.NoSuchAlgorithmException
|
||||||
import java.security.PublicKey
|
import java.security.PublicKey
|
||||||
|
import androidx.core.net.toUri
|
||||||
|
|
||||||
internal class SimpleSftpServer {
|
internal class SimpleSftpServer {
|
||||||
private lateinit var sshd: SshServer
|
private lateinit var sshd: SshServer
|
||||||
@ -110,7 +111,7 @@ internal class SimpleSftpServer {
|
|||||||
withFileSystemAccessor(object : SftpFileSystemAccessor {
|
withFileSystemAccessor(object : SftpFileSystemAccessor {
|
||||||
fun notifyMediaStore(path: Path) {
|
fun notifyMediaStore(path: Path) {
|
||||||
kotlin.runCatching {
|
kotlin.runCatching {
|
||||||
val uri = Uri.parse(path.toUri().toString())
|
val uri = path.toUri().toString().toUri()
|
||||||
MediaStoreHelper.indexFile(context, uri)
|
MediaStoreHelper.indexFile(context, uri)
|
||||||
uri
|
uri
|
||||||
}.fold(
|
}.fold(
|
||||||
|
@ -5,14 +5,12 @@
|
|||||||
*/
|
*/
|
||||||
package org.kde.kdeconnect.Plugins.SftpPlugin.saf
|
package org.kde.kdeconnect.Plugins.SftpPlugin.saf
|
||||||
|
|
||||||
import android.content.ContentValues
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.ParcelFileDescriptor
|
import android.os.ParcelFileDescriptor
|
||||||
import android.provider.DocumentsContract
|
import android.provider.DocumentsContract
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import org.kde.kdeconnect.Helpers.MediaStoreHelper
|
|
||||||
import java.io.FileNotFoundException
|
import java.io.FileNotFoundException
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.lang.reflect.Method
|
import java.lang.reflect.Method
|
||||||
|
@ -17,7 +17,6 @@ import android.webkit.URLUtil;
|
|||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.appcompat.app.ActionBar;
|
import androidx.appcompat.app.ActionBar;
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
|
||||||
import androidx.preference.PreferenceManager;
|
import androidx.preference.PreferenceManager;
|
||||||
|
|
||||||
import org.kde.kdeconnect.BackgroundService;
|
import org.kde.kdeconnect.BackgroundService;
|
||||||
|
@ -20,7 +20,6 @@ import org.kde.kdeconnect_tp.R;
|
|||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
@PluginFactory.LoadablePlugin
|
@PluginFactory.LoadablePlugin
|
||||||
|
@ -34,7 +34,6 @@ import org.kde.kdeconnect.UserInterface.PluginSettingsFragment;
|
|||||||
import org.kde.kdeconnect_tp.R;
|
import org.kde.kdeconnect_tp.R;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.Timer;
|
import java.util.Timer;
|
||||||
import java.util.TimerTask;
|
import java.util.TimerTask;
|
||||||
|
|
||||||
|
@ -21,6 +21,7 @@ import org.kde.kdeconnect.UserInterface.MainActivity
|
|||||||
import org.kde.kdeconnect.extensions.setupBottomPadding
|
import org.kde.kdeconnect.extensions.setupBottomPadding
|
||||||
import org.kde.kdeconnect_tp.R
|
import org.kde.kdeconnect_tp.R
|
||||||
import org.kde.kdeconnect_tp.databinding.FragmentAboutBinding
|
import org.kde.kdeconnect_tp.databinding.FragmentAboutBinding
|
||||||
|
import androidx.core.net.toUri
|
||||||
|
|
||||||
class AboutFragment : Fragment() {
|
class AboutFragment : Fragment() {
|
||||||
private var _binding: FragmentAboutBinding? = null
|
private var _binding: FragmentAboutBinding? = null
|
||||||
@ -113,7 +114,7 @@ class AboutFragment : Fragment() {
|
|||||||
button.visibility = View.GONE
|
button.visibility = View.GONE
|
||||||
} else {
|
} else {
|
||||||
button.setOnClickListener {
|
button.setOnClickListener {
|
||||||
startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(url)))
|
startActivity(Intent(Intent.ACTION_VIEW, url.toUri()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,7 @@ import androidx.appcompat.widget.TooltipCompat
|
|||||||
import org.kde.kdeconnect.UserInterface.List.ListAdapter
|
import org.kde.kdeconnect.UserInterface.List.ListAdapter
|
||||||
import org.kde.kdeconnect_tp.R
|
import org.kde.kdeconnect_tp.R
|
||||||
import org.kde.kdeconnect_tp.databinding.AboutPersonListItemEntryBinding
|
import org.kde.kdeconnect_tp.databinding.AboutPersonListItemEntryBinding
|
||||||
|
import androidx.core.net.toUri
|
||||||
|
|
||||||
class AboutPersonEntryItem(val person: AboutPerson) : ListAdapter.Item {
|
class AboutPersonEntryItem(val person: AboutPerson) : ListAdapter.Item {
|
||||||
override fun inflateView(layoutInflater: LayoutInflater): View {
|
override fun inflateView(layoutInflater: LayoutInflater): View {
|
||||||
@ -31,7 +32,8 @@ class AboutPersonEntryItem(val person: AboutPerson) : ListAdapter.Item {
|
|||||||
binding.aboutPersonListItemEntryVisitHomepageButton.visibility = View.VISIBLE
|
binding.aboutPersonListItemEntryVisitHomepageButton.visibility = View.VISIBLE
|
||||||
TooltipCompat.setTooltipText(binding.aboutPersonListItemEntryVisitHomepageButton, layoutInflater.context.resources.getString(R.string.visit_contributors_homepage, person.webAddress))
|
TooltipCompat.setTooltipText(binding.aboutPersonListItemEntryVisitHomepageButton, layoutInflater.context.resources.getString(R.string.visit_contributors_homepage, person.webAddress))
|
||||||
binding.aboutPersonListItemEntryVisitHomepageButton.setOnClickListener {
|
binding.aboutPersonListItemEntryVisitHomepageButton.setOnClickListener {
|
||||||
layoutInflater.context.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(person.webAddress)))
|
layoutInflater.context.startActivity(Intent(Intent.ACTION_VIEW,
|
||||||
|
person.webAddress.toUri()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -194,7 +194,7 @@ public class CustomDevicesActivity extends BaseActivity<ActivityCustomDevicesBin
|
|||||||
saveList();
|
saveList();
|
||||||
showEmptyListMessageIfRequired();
|
showEmptyListMessageIfRequired();
|
||||||
})
|
})
|
||||||
.addCallback(new BaseTransientBottomBar.BaseCallback<Snackbar>() {
|
.addCallback(new BaseTransientBottomBar.BaseCallback<>() {
|
||||||
@Override
|
@Override
|
||||||
public void onDismissed(Snackbar transientBottomBar, int event) {
|
public void onDismissed(Snackbar transientBottomBar, int event) {
|
||||||
switch (event) {
|
switch (event) {
|
||||||
@ -272,8 +272,8 @@ public class CustomDevicesActivity extends BaseActivity<ActivityCustomDevicesBin
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static class DeletedCustomDevice {
|
private static class DeletedCustomDevice {
|
||||||
@NonNull DeviceHost hostnameOrIP;
|
@NonNull final DeviceHost hostnameOrIP;
|
||||||
int position;
|
final int position;
|
||||||
|
|
||||||
DeletedCustomDevice(@NonNull DeviceHost hostnameOrIP, int position) {
|
DeletedCustomDevice(@NonNull DeviceHost hostnameOrIP, int position) {
|
||||||
this.hostnameOrIP = hostnameOrIP;
|
this.hostnameOrIP = hostnameOrIP;
|
||||||
|
@ -39,7 +39,9 @@ import org.kde.kdeconnect.UserInterface.About.AboutFragment
|
|||||||
import org.kde.kdeconnect.UserInterface.About.getApplicationAboutData
|
import org.kde.kdeconnect.UserInterface.About.getApplicationAboutData
|
||||||
import org.kde.kdeconnect_tp.R
|
import org.kde.kdeconnect_tp.R
|
||||||
import org.kde.kdeconnect_tp.databinding.ActivityMainBinding
|
import org.kde.kdeconnect_tp.databinding.ActivityMainBinding
|
||||||
import java.util.LinkedList
|
import androidx.core.content.edit
|
||||||
|
import androidx.core.view.size
|
||||||
|
import androidx.core.view.get
|
||||||
|
|
||||||
private const val MENU_ENTRY_ADD_DEVICE = 1 //0 means no-selection
|
private const val MENU_ENTRY_ADD_DEVICE = 1 //0 means no-selection
|
||||||
private const val MENU_ENTRY_SETTINGS = 2
|
private const val MENU_ENTRY_SETTINGS = 2
|
||||||
@ -59,7 +61,7 @@ class MainActivity : AppCompatActivity(), OnSharedPreferenceChangeListener {
|
|||||||
|
|
||||||
private var mCurrentDevice: String? = null
|
private var mCurrentDevice: String? = null
|
||||||
private var mCurrentMenuEntry = 0
|
private var mCurrentMenuEntry = 0
|
||||||
private set(value) {
|
set(value) {
|
||||||
field = value
|
field = value
|
||||||
//Enabling "go to default fragment on back" callback when user in settings or "about" fragment
|
//Enabling "go to default fragment on back" callback when user in settings or "about" fragment
|
||||||
mainFragmentCallback.isEnabled = value == MENU_ENTRY_SETTINGS || value == MENU_ENTRY_ABOUT
|
mainFragmentCallback.isEnabled = value == MENU_ENTRY_SETTINGS || value == MENU_ENTRY_ABOUT
|
||||||
@ -87,7 +89,7 @@ class MainActivity : AppCompatActivity(), OnSharedPreferenceChangeListener {
|
|||||||
|
|
||||||
val root = binding.root
|
val root = binding.root
|
||||||
setContentView(root)
|
setContentView(root)
|
||||||
mDrawerLayout = if (root is DrawerLayout) root else null
|
mDrawerLayout = root as? DrawerLayout
|
||||||
|
|
||||||
val mDrawerHeader = mNavigationView.getHeaderView(0)
|
val mDrawerHeader = mNavigationView.getHeaderView(0)
|
||||||
mNavViewDeviceName = mDrawerHeader.findViewById(R.id.device_name)
|
mNavViewDeviceName = mDrawerHeader.findViewById(R.id.device_name)
|
||||||
@ -115,17 +117,17 @@ class MainActivity : AppCompatActivity(), OnSharedPreferenceChangeListener {
|
|||||||
when (mCurrentMenuEntry) {
|
when (mCurrentMenuEntry) {
|
||||||
MENU_ENTRY_ADD_DEVICE -> {
|
MENU_ENTRY_ADD_DEVICE -> {
|
||||||
mCurrentDevice = null
|
mCurrentDevice = null
|
||||||
preferences.edit().putString(STATE_SELECTED_DEVICE, null).apply()
|
preferences.edit { putString(STATE_SELECTED_DEVICE, null) }
|
||||||
setContentFragment(PairingFragment())
|
setContentFragment(PairingFragment())
|
||||||
}
|
}
|
||||||
|
|
||||||
MENU_ENTRY_SETTINGS -> {
|
MENU_ENTRY_SETTINGS -> {
|
||||||
preferences.edit().putString(STATE_SELECTED_DEVICE, null).apply()
|
preferences.edit { putString(STATE_SELECTED_DEVICE, null) }
|
||||||
setContentFragment(SettingsFragment())
|
setContentFragment(SettingsFragment())
|
||||||
}
|
}
|
||||||
|
|
||||||
MENU_ENTRY_ABOUT -> {
|
MENU_ENTRY_ABOUT -> {
|
||||||
preferences.edit().putString(STATE_SELECTED_DEVICE, null).apply()
|
preferences.edit { putString(STATE_SELECTED_DEVICE, null) }
|
||||||
setContentFragment(AboutFragment.newInstance(getApplicationAboutData(this)))
|
setContentFragment(AboutFragment.newInstance(getApplicationAboutData(this)))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -207,7 +209,7 @@ class MainActivity : AppCompatActivity(), OnSharedPreferenceChangeListener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(missingPermissions.size > 0){
|
if(missingPermissions.isNotEmpty()){
|
||||||
ActivityCompat.requestPermissions(this, missingPermissions.toTypedArray(), RESULT_NOTIFICATIONS_ENABLED)
|
ActivityCompat.requestPermissions(this, missingPermissions.toTypedArray(), RESULT_NOTIFICATIONS_ENABLED)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -303,7 +305,7 @@ class MainActivity : AppCompatActivity(), OnSharedPreferenceChangeListener {
|
|||||||
@JvmOverloads
|
@JvmOverloads
|
||||||
fun onDeviceSelected(deviceId: String?, fromDeviceList: Boolean = false) {
|
fun onDeviceSelected(deviceId: String?, fromDeviceList: Boolean = false) {
|
||||||
mCurrentDevice = deviceId
|
mCurrentDevice = deviceId
|
||||||
preferences.edit().putString(STATE_SELECTED_DEVICE, deviceId).apply()
|
preferences.edit { putString(STATE_SELECTED_DEVICE, deviceId) }
|
||||||
if (mCurrentDevice != null) {
|
if (mCurrentDevice != null) {
|
||||||
mCurrentMenuEntry = deviceIdToMenuEntryId(deviceId)
|
mCurrentMenuEntry = deviceIdToMenuEntryId(deviceId)
|
||||||
if (mCurrentMenuEntry == MENU_ENTRY_DEVICE_UNKNOWN) {
|
if (mCurrentMenuEntry == MENU_ENTRY_DEVICE_UNKNOWN) {
|
||||||
@ -364,9 +366,9 @@ class MainActivity : AppCompatActivity(), OnSharedPreferenceChangeListener {
|
|||||||
|
|
||||||
if (isPermissionGranted(permissions, grantResults, Manifest.permission.BLUETOOTH_CONNECT) &&
|
if (isPermissionGranted(permissions, grantResults, Manifest.permission.BLUETOOTH_CONNECT) &&
|
||||||
isPermissionGranted(permissions, grantResults, Manifest.permission.BLUETOOTH_SCAN)) {
|
isPermissionGranted(permissions, grantResults, Manifest.permission.BLUETOOTH_SCAN)) {
|
||||||
val preferenceEditor = PreferenceManager.getDefaultSharedPreferences(this).edit()
|
PreferenceManager.getDefaultSharedPreferences(this).edit {
|
||||||
preferenceEditor.putBoolean(SettingsFragment.KEY_BLUETOOTH_ENABLED, true)
|
putBoolean(SettingsFragment.KEY_BLUETOOTH_ENABLED, true)
|
||||||
preferenceEditor.apply()
|
}
|
||||||
setContentFragment(SettingsFragment())
|
setContentFragment(SettingsFragment())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -390,9 +392,9 @@ class MainActivity : AppCompatActivity(), OnSharedPreferenceChangeListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun uncheckAllMenuItems(menu: Menu) {
|
private fun uncheckAllMenuItems(menu: Menu) {
|
||||||
val size = menu.size()
|
val size = menu.size
|
||||||
for (i in 0 until size) {
|
for (i in 0 until size) {
|
||||||
val item = menu.getItem(i)
|
val item = menu[i]
|
||||||
item.subMenu?.let { uncheckAllMenuItems(it) } ?: item.setChecked(false)
|
item.subMenu?.let { uncheckAllMenuItems(it) } ?: item.setChecked(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,6 @@
|
|||||||
package org.kde.kdeconnect.UserInterface
|
package org.kde.kdeconnect.UserInterface
|
||||||
|
|
||||||
import android.Manifest
|
import android.Manifest
|
||||||
import android.app.Activity
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.pm.PackageManager
|
import android.content.pm.PackageManager
|
||||||
|
@ -6,9 +6,8 @@
|
|||||||
package org.kde.kdeconnect.UserInterface
|
package org.kde.kdeconnect.UserInterface
|
||||||
|
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.net.Uri
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import org.apache.commons.lang3.StringUtils
|
import androidx.core.net.toUri
|
||||||
|
|
||||||
class StartActivityAlertDialogFragment : AlertDialogFragment() {
|
class StartActivityAlertDialogFragment : AlertDialogFragment() {
|
||||||
private var intentAction: String? = null
|
private var intentAction: String? = null
|
||||||
@ -36,8 +35,9 @@ class StartActivityAlertDialogFragment : AlertDialogFragment() {
|
|||||||
|
|
||||||
setCallback(object : Callback() {
|
setCallback(object : Callback() {
|
||||||
override fun onPositiveButtonClicked() {
|
override fun onPositiveButtonClicked() {
|
||||||
|
val intentUrl = intentUrl
|
||||||
val intent = if (!intentUrl.isNullOrEmpty()) {
|
val intent = if (!intentUrl.isNullOrEmpty()) {
|
||||||
Intent(intentAction, Uri.parse(intentUrl))
|
Intent(intentAction, intentUrl.toUri())
|
||||||
} else {
|
} else {
|
||||||
Intent(intentAction)
|
Intent(intentAction)
|
||||||
}
|
}
|
||||||
|
@ -9,8 +9,11 @@ package org.kde.kdeconnect.UserInterface.compose
|
|||||||
import androidx.compose.foundation.layout.RowScope
|
import androidx.compose.foundation.layout.RowScope
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.automirrored.filled.ArrowBack
|
import androidx.compose.material.icons.automirrored.filled.ArrowBack
|
||||||
import androidx.compose.material.icons.filled.ArrowBack
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
import androidx.compose.material3.*
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.IconButton
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.material3.TopAppBar
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.graphics.vector.ImageVector
|
import androidx.compose.ui.graphics.vector.ImageVector
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
|
@ -6,7 +6,6 @@
|
|||||||
package org.kde.kdeconnect.async
|
package org.kde.kdeconnect.async
|
||||||
|
|
||||||
import java.util.concurrent.atomic.AtomicLong
|
import java.util.concurrent.atomic.AtomicLong
|
||||||
import kotlin.concurrent.Volatile
|
|
||||||
|
|
||||||
abstract class BackgroundJob<I, R> : Runnable {
|
abstract class BackgroundJob<I, R> : Runnable {
|
||||||
private val callback: Callback<R>
|
private val callback: Callback<R>
|
||||||
|
@ -129,7 +129,7 @@ class DeviceTest {
|
|||||||
val deviceId = "testDevice"
|
val deviceId = "testDevice"
|
||||||
val settings = context.getSharedPreferences(deviceId, Context.MODE_PRIVATE)
|
val settings = context.getSharedPreferences(deviceId, Context.MODE_PRIVATE)
|
||||||
val deviceInfo = loadFromSettings(context, deviceId, settings)
|
val deviceInfo = loadFromSettings(context, deviceId, settings)
|
||||||
deviceInfo.protocolVersion = DeviceHelper.ProtocolVersion
|
deviceInfo.protocolVersion = DeviceHelper.PROTOCOL_VERSION
|
||||||
deviceInfo.incomingCapabilities = hashSetOf("kdeconnect.plugin1State", "kdeconnect.plugin2State")
|
deviceInfo.incomingCapabilities = hashSetOf("kdeconnect.plugin1State", "kdeconnect.plugin2State")
|
||||||
deviceInfo.outgoingCapabilities = hashSetOf("kdeconnect.plugin1State.request", "kdeconnect.plugin2State.request")
|
deviceInfo.outgoingCapabilities = hashSetOf("kdeconnect.plugin1State.request", "kdeconnect.plugin2State.request")
|
||||||
|
|
||||||
@ -208,7 +208,7 @@ class DeviceTest {
|
|||||||
val deviceId = "unpairedTestDevice"
|
val deviceId = "unpairedTestDevice"
|
||||||
fakeNetworkPacket["deviceId"] = deviceId
|
fakeNetworkPacket["deviceId"] = deviceId
|
||||||
fakeNetworkPacket["deviceName"] = "Unpaired Test Device"
|
fakeNetworkPacket["deviceName"] = "Unpaired Test Device"
|
||||||
fakeNetworkPacket["protocolVersion"] = DeviceHelper.ProtocolVersion
|
fakeNetworkPacket["protocolVersion"] = DeviceHelper.PROTOCOL_VERSION
|
||||||
fakeNetworkPacket["deviceType"] = DeviceType.PHONE.toString()
|
fakeNetworkPacket["deviceType"] = DeviceType.PHONE.toString()
|
||||||
val certificateString =
|
val certificateString =
|
||||||
"""
|
"""
|
||||||
|
@ -12,7 +12,6 @@ import org.junit.Before
|
|||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.kde.kdeconnect.Helpers.SecurityHelpers.SslHelper
|
import org.kde.kdeconnect.Helpers.SecurityHelpers.SslHelper
|
||||||
import org.kde.kdeconnect.MockSharedPreference
|
import org.kde.kdeconnect.MockSharedPreference
|
||||||
import org.kde.kdeconnect.PairingHandler
|
|
||||||
import org.mockito.ArgumentMatchers
|
import org.mockito.ArgumentMatchers
|
||||||
import org.mockito.MockedStatic
|
import org.mockito.MockedStatic
|
||||||
import org.mockito.Mockito
|
import org.mockito.Mockito
|
||||||
|
Loading…
x
Reference in New Issue
Block a user