2
0
mirror of https://github.com/KDE/kdeconnect-android synced 2025-09-01 06:35:09 +00:00

Compare commits

...

152 Commits

Author SHA1 Message Date
Albert Vaca
23648a03e5 Bumped version to release 2017-05-16 21:05:17 +02:00
Simon Redman
3f188b5526 Add support for sending and receiving multipart SMSes
Summary:
The SMS protocol does not support sending a message longer than 160 characters. Android's SmsManager.sendTextMessage(..) fails to send in case the message is too long.
Instead of failing, check the message length. If it is longer than 160 characters, break it up and send it as several messages

On receive, collect the list of messages, then combine their bodies

Test Plan:
Send a long message via KDE Connect and verify that it is actually sent
Send a short message via KDE Connect and verify that it can also be sent
Ideally: Test sending a message which is the maximum length for an SMS (160 characters) and verify that it is sent as exactly one SMS (And billed properly)

Receive a long message and verify that it is delivered as a single long message, even though we all know that it was transmitted as a multi-part SMS
Receive a short message and verify that it is correctly delivered

Reviewers: #kde_connect, albertvaka

Reviewed By: #kde_connect, albertvaka

Subscribers: albertvaka

Differential Revision: https://phabricator.kde.org/D5848
2017-05-16 21:03:59 +02:00
Albert Vaca
2d35b04713 Fix IllegalStateException: Fragment not attached to Activity
BUG: 379873
2017-05-16 21:01:45 +02:00
Albert Vaca
9a5b03c423 Fixing crash, apparently info can be null (?) 2017-05-16 21:01:45 +02:00
l10n daemon script
ee336aa414 GIT_SILENT made messages (after extraction) 2017-05-15 05:02:35 +02:00
Albert Vaca
a81eba9ea1 Bumped version number to release 2017-05-06 14:29:24 +02:00
Nicholas Killewald
c5022358de Made getLocalIpAddress ignore rmnet-related interfaces.
Any interface with "rmnet" in it is an internal interface that has to do
with the device's cellular connection or USB tethering.  Since those
interfaces might give IPv4 addresses that are unreachable from any other
device, this change makes getLocalIpAddress ignore anything rmnet-related.

BUG: 337685
2017-05-06 14:26:55 +02:00
Albert Vaca
9d1734406b Bumped version number to release 2017-05-06 12:54:06 +02:00
Albert Vaca
2d49715891 Removed print 2017-05-06 12:47:51 +02:00
Albert Vaca
9e6a4938ed Added an extra check to be really sure we are on data. 2017-05-06 12:47:46 +02:00
Albert Vaca
cc4a196334 Make android version check lint happy 2017-05-06 12:46:52 +02:00
Albert Vaca
c39620e33c Update gradle plugin 2017-05-06 12:38:04 +02:00
Albert Vaca
0dd26e5729 Removed an if to check for access to "/" as it never helped 2017-05-06 12:19:36 +02:00
l10n daemon script
86d0d3065c GIT_SILENT made messages (after extraction) 2017-03-14 19:05:45 +01:00
l10n daemon script
1f8f39a7f8 GIT_SILENT made messages (after extraction) 2017-03-09 06:56:51 +01:00
l10n daemon script
05ba2188de GIT_SILENT made messages (after extraction) 2017-03-05 08:01:12 +01:00
l10n daemon script
ba440bd5ea GIT_SILENT made messages (after extraction) 2017-03-04 07:13:18 +01:00
l10n daemon script
a94e082b68 GIT_SILENT made messages (after extraction) 2017-03-01 06:45:54 +01:00
Albert Vaca
def0cad889 Further refining the network detection 2017-02-28 21:21:51 +01:00
Albert Vaca
c93e4400e2 Fix crash when fragment.getContext() was null 2017-02-25 21:42:34 +01:00
Albert Vaca
9580154a13 Bumped version to release 2017-02-25 21:32:28 +01:00
Albert Vaca
48f5566326 Try a different approach to detect when on mobile data. 2017-02-25 21:25:06 +01:00
Albert Vaca
3ea5d43b99 Revert "Do not broadcast in 3G + info message"
As it couldn't be any other way, this broke somebody's workflow.

This reverts commit 440a12f86c.
2017-02-25 21:06:40 +01:00
l10n daemon script
a172430c11 GIT_SILENT made messages (after extraction) 2017-02-23 07:12:52 +01:00
l10n daemon script
b4b7b58cb2 GIT_SILENT made messages (after extraction) 2017-02-21 13:33:16 +01:00
Albert Vaca
8d99de59fc Fix crash on Android < 12 2017-02-20 22:59:52 +01:00
Albert Vaca
337cdba68f Prepare beta release 2017-02-20 20:36:55 +01:00
Albert Vaca
b3e1f6fbf8 Preparing a hotfix release 2017-02-20 20:25:02 +01:00
Albert Vaca
ecad7ccea2 Try not to lose filename extensions.
Android's Storage Access Framework abstraction wants us to use mimetypes
instead of file extensions, but for some file types it can't guess a useful
mimetype. In those cases, provide the extension as part of the base name.

BUG: 376638
2017-02-20 20:20:54 +01:00
l10n daemon script
b7df5348c0 GIT_SILENT made messages (after extraction) 2017-02-20 06:44:38 +01:00
Albert Vaca
440a12f86c Do not broadcast in 3G + info message 2017-02-18 19:06:37 +01:00
Albert Vaca
0e3b5af6bc Looks like it's not 2017-02-18 17:41:12 +01:00
Albert Vaca
b167b9629e Changed visibilities to package-private 2017-02-18 17:16:10 +01:00
Albert Vaca
b6814c86c5 Bumped version to release 2017-02-14 22:23:33 +01:00
Dmitriy Bogdanov
3cc71a69a4 FindMyPhone: better activity lifecycle handling
Summary:
There are some minor problems with current implementation: if device configuration changes (screen orientation, etc.) while the "FindMyPhone" ringtone is playing, the activity gets recreated and starts to play a new ringtone again, but the first ringtone is not stopped.
Also if the user leaves the activity the ringtone continues to play, the user has no way to get back to the activity to stop it.

With these changes the ringtone starts playing when the activity becomes visible and stops when the activity is being hidden/destroyed. If the user leaves the activity (without destroying it) and then presses "Ring my phone" button again, the activity becomes visible again and starts to play the ringtone.

There are other ways to improve it that I did not touch: use a Service to play the ringtone (so not to depend on the activity's lifecycle) or handle configuration changes in activity (so it is not recreated on orientation changes).

Test Plan: Activate "Find My Phone" feature and try to turn phone or leave activity.

Reviewers: albertvaka

Reviewed By: albertvaka

Tags: #kde_connect

Differential Revision: https://phabricator.kde.org/D4548
2017-02-14 22:12:38 +01:00
l10n daemon script
c0502803c4 GIT_SILENT made messages (after extraction) 2017-02-12 06:34:40 +01:00
l10n daemon script
ec6696b33b GIT_SILENT made messages (after extraction) 2017-02-11 06:59:47 +01:00
l10n daemon script
7e30e27f61 GIT_SILENT made messages (after extraction) 2017-02-10 06:30:56 +01:00
l10n daemon script
92a10bcd35 GIT_SILENT made messages (after extraction) 2017-02-08 06:21:40 +01:00
l10n daemon script
723f398ea8 GIT_SILENT made messages (after extraction) 2017-02-07 13:35:11 +01:00
l10n daemon script
060fa8200e GIT_SILENT made messages (after extraction) 2017-02-06 06:55:43 +01:00
Albert Vaca
7045c50c81 OPEN_DOCUMENT_TREE needs lollipop 2017-02-05 21:39:28 +01:00
Albert Vaca
fe0409e9e7 Bumped version to release in beta channel 2017-02-05 21:31:49 +01:00
Albert Vaca
4f39aa2b65 Disabled remote keyboard from stable branch
Se we can release from the stable branch without it until we release a
desktop version with this feature.
2017-02-05 21:31:34 +01:00
Albert Vaca
cba67c73a0 Fixed tests 2017-02-05 21:24:45 +01:00
Albert Vaca
2e5dc56366 Merge branch '1.x'
# Conflicts:
#	res/values-ast/strings.xml
#	res/values-gl/strings.xml
2017-02-05 21:23:13 +01:00
Albert Vaca
5ece4e21e7 Bumped android sdk version 2017-02-05 16:19:55 +01:00
Albert Vaca
be66fb23cf Stuff used from inner classes shouldn't be private. 2017-02-05 16:19:41 +01:00
Albert Vaca
a6bd803df8 Fixed NPE because frag.device was null
Why was this starting two RunCommand threads? Exec order is not guaranteed.
2017-02-05 15:42:03 +01:00
Albert Vaca
a5a4b360ae Fixed crash on unpairing 2017-02-05 15:34:16 +01:00
Albert Vaca
71e7218b4e Fixed java.lang.ClassCastException:
android.text.SpannableString cannot be cast to java.lang.String
2017-02-05 15:34:07 +01:00
Okoko Michaels
89ecdfc363 Accept or reject pair requests from the notification 2017-02-05 15:20:36 +01:00
l10n daemon script
1179807bcf GIT_SILENT made messages (after extraction) 2017-02-05 03:53:51 +01:00
l10n daemon script
4279ae824f GIT_SILENT made messages (after extraction) 2017-02-02 06:45:38 +01:00
l10n daemon script
753a6425ef GIT_SILENT made messages (after extraction) 2017-02-02 03:50:38 +01:00
l10n daemon script
08312e409d GIT_SILENT made messages (after extraction) 2017-01-31 08:49:33 +01:00
l10n daemon script
22526fdaa8 GIT_SILENT made messages (after extraction) 2017-01-30 03:47:18 +01:00
l10n daemon script
963b29ef6b GIT_SILENT made messages (after extraction) 2017-01-25 03:51:08 +01:00
Holger Kaelberer
ca9704eab2 Add remotekeyboard plugin
BUG: 370919
REVIEW: 129728
2017-01-23 09:07:18 +01:00
l10n daemon script
8d148aad92 GIT_SILENT made messages (after extraction) 2017-01-23 06:35:43 +01:00
l10n daemon script
1239944deb GIT_SILENT made messages (after extraction) 2017-01-23 03:43:48 +01:00
Albert Vaca
9e5e9b3047 Make package private 2017-01-22 06:08:07 +01:00
l10n daemon script
42f8289071 GIT_SILENT made messages (after extraction) 2017-01-15 04:03:15 +01:00
l10n daemon script
371ffefd20 GIT_SILENT made messages (after extraction) 2017-01-07 07:20:26 +01:00
l10n daemon script
614becd1a7 GIT_SILENT made messages (after extraction) 2017-01-07 03:41:41 +01:00
l10n daemon script
3c101210e2 GIT_SILENT made messages (after extraction) 2017-01-04 07:02:02 +01:00
l10n daemon script
52a4ac20ee GIT_SILENT made messages (after extraction) 2016-12-27 13:30:52 +01:00
l10n daemon script
42be344336 GIT_SILENT made messages (after extraction) 2016-12-26 06:42:43 +01:00
l10n daemon script
1811b93b0a GIT_SILENT made messages (after extraction) 2016-12-26 03:35:38 +01:00
Albert Vaca
6ed1bf6284 Fix crash when ringtone is null. 2016-12-25 16:57:32 +01:00
l10n daemon script
f1ca9a3c33 GIT_SILENT made messages (after extraction) 2016-12-22 06:40:55 +01:00
l10n daemon script
9d4bbbb629 GIT_SILENT made messages (after extraction) 2016-12-22 03:37:14 +01:00
l10n daemon script
60ff59bc34 GIT_SILENT made messages (after extraction) 2016-12-20 14:13:07 +01:00
l10n daemon script
059a3b2437 GIT_SILENT made messages (after extraction) 2016-12-20 08:31:20 +01:00
Albert Vaca
eeb19bd206 Allow sending more than one file from SendFileActivity 2016-12-19 09:19:40 +01:00
l10n daemon script
5e229085e9 GIT_SILENT made messages (after extraction) 2016-12-19 06:22:52 +01:00
l10n daemon script
a7c4bbd379 GIT_SILENT made messages (after extraction) 2016-12-18 06:17:35 +01:00
l10n daemon script
a38ffe34bd GIT_SILENT made messages (after extraction) 2016-12-18 03:44:15 +01:00
Albert Vaca
b5e6519efe Increased versio number to release 2016-12-17 15:33:09 +01:00
l10n daemon script
ad2b7678b9 GIT_SILENT made messages (after extraction) 2016-12-16 03:35:24 +01:00
l10n daemon script
9649efcdc4 GIT_SILENT made messages (after extraction) 2016-12-14 02:48:48 +01:00
l10n daemon script
99b7c4f312 GIT_SILENT made messages (after extraction) 2016-12-13 02:39:05 +01:00
l10n daemon script
c80820294c GIT_SILENT made messages (after extraction) 2016-12-12 02:34:13 +01:00
Albert Vaca
90856690fb Increased version number to release in the beta channel 2016-12-11 21:22:13 +01:00
Albert Vaca
1334dae342 Added a Share setting to add received files to the "Downloads" app
Only works for old-school (not-Storage Access Framework) paths, so we have
to keep track of the fact that we are using one or the other.

Also this requires the permission DOWNLOAD_WITHOUT_NOTIFICATION, but
hopefully the play store won't make users confirm this one.

This behaviour is enabled by default.
2016-12-11 21:03:39 +01:00
Albert Vaca
f8dd9bf923 Fixed crash if received file didn't have extension 2016-12-11 20:27:52 +01:00
Albert Vaca
72d8ba647a If transfer failed, don't create a pending intent nor index the file 2016-12-11 19:19:51 +01:00
Albert Vaca
b3449c87f7 Rewritten ShareSettingsActivity and de-duplicated SAF code in SharePlugin.
There was unused code and incorrect comments that were introduced in
commit e2e4086.
2016-12-11 18:57:21 +01:00
Albert Vaca
5c3b5a2737 Fixed comment as MayeulC suggested on IRC 2016-12-11 16:40:11 +01:00
Richard Wagler
e2e40863f8 Implement saving to SD card using SAF 2016-12-11 14:01:46 +01:00
Albert Vaca
036737deae Unused imports 2016-12-11 14:00:55 +01:00
Albert Vaca
8d7337b6b0 Refactored media scanner call into MediaStoreHelper 2016-12-11 13:59:52 +01:00
Albert Vaca
0a4459e8a0 Made Sftp server notify the Android MediaScanner of new/removed files
Plus refactored the code a bit to simplify logic
2016-12-11 13:59:00 +01:00
Albert Vaca
cef8cbd34a Android Studio update 2016-12-11 13:59:00 +01:00
l10n daemon script
3afb8ae8f3 GIT_SILENT made messages (after extraction) 2016-12-11 02:35:14 +01:00
l10n daemon script
85fce32bcb GIT_SILENT made messages (after extraction) 2016-12-10 02:32:33 +01:00
Albert Vaca
d52be109ee Revert "Add support to deal with album arts sent by mpris plugin."
This was very poorly implemented and can't stay as it is right now:
 - Every second or so the art image was being loaded from disk, scaled,
   base64 encoded and sent over the freakin network!
 - The Android interface didn't take into account small screens, and
   adding the image would cut stuff out of the screen.
 - Didn't manage "edge cases" like playing a song without cover after one
   with cover (previous image was still being shown) or changing players.

This reverts commit 24c404400f.

# Conflicts:
#	src/org/kde/kdeconnect/Plugins/MprisPlugin/MprisActivity.java
#	src/org/kde/kdeconnect/Plugins/MprisPlugin/MprisPlugin.java
2016-12-08 23:47:17 +01:00
Albert Vaca
66794002f7 Updated version number to release in the beta channel/ 2016-12-08 20:53:40 +01:00
Albert Vaca
d61536ef76 Improved sharing files.
- Refactored the code to separate reading the file, sending it and
  updating the notification. This last part it's now done in a standalone
  sendPackage callback class.
- Added a non-async sendPacakge function to device, so we can properly
  wait for a file to finish before sending the next one without using
  recursive callbacks as before.
- Fixed bug that made it impossible to share more than one file from
  certain apps. This was caused because we can't access content resolvers
  any longer after closing the activity that was launched to "share" to.
  Now we do the content resolutions first and once for all files.
- When sending more than one file, do not spam one notification for each.
- There is no need to update the notifications from the UI thread, now
  we do it from a background thread instead.
2016-12-08 20:50:49 +01:00
Albert Vaca
1dad3c145d Make onProgressChanged updates time-based.
If used to update a notification, calling it too often would lag the UI
2016-12-08 20:50:49 +01:00
Albert Vaca
33f7a4809d Don't call onProgressChanged unless it actually changes 2016-12-08 20:50:49 +01:00
Albert Vaca
d81448ad34 Fixed LanLink always calling onProgressChanged with a progress of 0 2016-12-08 20:50:49 +01:00
Albert Vaca
ed4c0d24df Introduced NotificationHelper 2016-12-08 20:50:49 +01:00
Albert Vaca
fed9bb1eec Not an error 2016-12-08 20:50:49 +01:00
Albert Vaca
b7418c1db6 Socket should be volatile to prevent data-race
CCBUG: 368438
2016-12-08 20:50:49 +01:00
Albert Vaca
e6bc78f013 Some refactoring on sendpackage to reduce allocations of empty callbacks 2016-12-08 20:50:49 +01:00
Albert Vaca
22de200cbf Typo 2016-12-08 20:50:49 +01:00
Albert Vaca
22dde07892 Typo 2016-12-08 20:50:49 +01:00
Albert Vaca
f9bdfb9fbd Not actually an error 2016-12-08 20:50:49 +01:00
Albert Vaca
9d6476a27e Moved the code around to split it in big blocks and add some comments 2016-12-08 20:50:49 +01:00
Albert Vaca
29a8db9c45 On error show an error message, not a success message :) 2016-12-08 20:50:49 +01:00
l10n daemon script
6e1f8e1496 SVN_SILENT made messages (after extraction) 2016-11-29 03:03:55 +01:00
Albert Vaca
82b15292fb Merge branch '1.x' 2016-11-28 14:48:39 +01:00
Albert Vaca
32f9f3b76a Update gradle plugin to make Android Studio happy 2016-11-28 14:48:22 +01:00
Albert Vaca
fc25e42196 Remove FindMyPhoneActivity from the application switcher,
because returning to it would make it to ring again.
2016-11-23 18:34:31 +01:00
l10n daemon script
db3422268f SVN_SILENT made messages (after extraction) 2016-11-05 07:16:39 +00:00
l10n daemon script
71bef30624 SVN_SILENT made messages (after extraction) 2016-10-28 10:31:23 +00:00
l10n daemon script
15e0188538 SVN_SILENT made messages (after extraction) 2016-10-28 06:56:05 +00:00
l10n daemon script
8bc8a47e9d SVN_SILENT made messages (after extraction) 2016-10-17 10:38:49 +00:00
l10n daemon script
ad7769edde SVN_SILENT made messages (after extraction) 2016-10-17 06:58:14 +00:00
l10n daemon script
a2c51a16ee SVN_SILENT made messages (after extraction) 2016-10-14 10:45:01 +00:00
l10n daemon script
788555b69c SVN_SILENT made messages (after extraction) 2016-10-14 07:05:25 +00:00
l10n daemon script
ccdeb3d806 SVN_SILENT made messages (after extraction) 2016-10-07 07:02:29 +00:00
l10n daemon script
00a5ad3c1f SVN_SILENT made messages (after extraction) 2016-09-30 10:42:37 +00:00
Albert Vaca
b35ce0f821 Do not clear values if the player didn't actually change 2016-09-29 14:15:31 +02:00
Albert Vaca
77e38da2d9 Fixed spotify hacks and moved them to a single function in the code 2016-09-29 14:14:55 +02:00
Albert Vaca
8fb942ccdf Nothing changes in this function, no need to update the list. 2016-09-29 13:21:31 +02:00
Albert Vaca
74dc1bcd63 Reduced logging. Renamed variables in camelcase. 2016-09-29 13:21:13 +02:00
Albert Vaca
0f655cf4eb Added a check to see if the dialog is already open.
If tapping fast, two dialogs could be opened. Opening it twice caused the
second dialog to segfault on tapping yes.
2016-09-29 13:20:43 +02:00
Albert Vaca
0de86785f8 Merge branch 'master' into 1.x
# Conflicts:
#	res/values-da/strings.xml
2016-09-29 13:01:25 +02:00
Thomas Posch
5320c3c226 Make commands sorted by name
BUG: 369239
2016-09-29 12:57:22 +02:00
l10n daemon script
7234b34db7 SVN_SILENT made messages (after extraction) 2016-09-28 10:26:51 +00:00
l10n daemon script
428fa947a4 SVN_SILENT made messages (after extraction) 2016-09-25 10:36:05 +00:00
Albert Vaca
b454dec0a0 Merge branch '1.x' 2016-09-24 20:34:03 +02:00
Albert Vaca
6c3811a0af Merge branch '1.x' 2016-09-20 12:47:50 +02:00
Albert Vaca
86245a697e Print a warning if device name is not in the list of human readable names. 2016-09-19 16:20:35 +02:00
Albert Vaca
041f172195 Merge remote-tracking branch 'origin/1.x' 2016-09-19 16:19:21 +02:00
l10n daemon script
6c1dcda744 SVN_SILENT made messages (after extraction) 2016-09-18 07:04:53 +00:00
l10n daemon script
91913664be SVN_SILENT made messages (after extraction) 2016-09-14 06:53:53 +00:00
Albert Vaca
9e680d1494 Merge branch '1.x' 2016-09-13 16:58:41 +02:00
Albert Vaca
4158a14437 Merge branch '1.x' 2016-09-12 17:15:06 +02:00
l10n daemon script
28a33172ce SVN_SILENT made messages (after extraction) 2016-09-08 07:23:50 +00:00
l10n daemon script
086194c629 SVN_SILENT made messages (after extraction) 2016-09-01 07:22:43 +00:00
Albert Vaca
75eca915dd Merge branch 'master' of git.kde.org:kdeconnect-android 2016-08-29 11:54:08 +02:00
Albert Vaca
cfcf9d97e7 Merge branch '1.x' 2016-08-29 11:53:49 +02:00
l10n daemon script
4acf931f5a SVN_SILENT made messages (after extraction) 2016-08-27 07:23:55 +00:00
Saikrishna Arcot
e95265c263 MPRIS: Read and apply the allowed actions for the player.
Read list of allowed actions for the player sent from KDE, and hide
buttons that perform actions that aren't allowed based on MPRIS.

REVIEW: 128273
2016-08-26 11:12:58 +02:00
Albert Vaca
fa689bace6 Merge branch '1.x' 2016-08-26 11:06:43 +02:00
l10n daemon script
625bdd36e3 SVN_SILENT made messages (after extraction) 2016-08-19 07:02:54 +00:00
l10n daemon script
717bb081a7 SVN_SILENT made messages (after extraction) 2016-08-08 06:58:25 +00:00
l10n daemon script
9d612192e3 SVN_SILENT made messages (after extraction) 2016-08-06 07:27:45 +00:00
l10n daemon script
4b171e624f SVN_SILENT made messages (after extraction) 2016-07-17 07:34:28 +00:00
104 changed files with 2508 additions and 668 deletions

View File

@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.kde.kdeconnect_tp"
android:versionCode="1440"
android:versionName="1.4.4">
android:versionCode="1630"
android:versionName="1.6.3">
<uses-sdk android:minSdkVersion="9"
android:targetSdkVersion="22" />
@@ -27,6 +27,7 @@
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.DOWNLOAD_WITHOUT_NOTIFICATION" />
<application
android:allowBackup="true"
@@ -41,6 +42,17 @@
android:enabled="true" >
</service>
<!--Commented here and in PluginFactory until we release a desktop version with this feature, so we don't get bad "feature not working" reviews-->
<!--
<service android:name="org.kde.kdeconnect.Plugins.RemoteKeyboardPlugin.RemoteKeyboardService"
android:label="KDE Connect Remote Keyboard"
android:permission="android.permission.BIND_INPUT_METHOD">
<intent-filter>
<action android:name="android.view.InputMethod" />
</intent-filter>
<meta-data android:name="android.view.im" android:resource="@xml/remotekeyboardplugin_method" />
</service>
-->
<activity
android:name="org.kde.kdeconnect.UserInterface.MaterialActivity"
android:label="KDE Connect"
@@ -83,6 +95,16 @@
android:name="android.support.PARENT_ACTIVITY"
android:value="org.kde.kdeconnect.UserInterface.SettingsActivity" />
</activity>
<activity
android:name="org.kde.kdeconnect.Plugins.SharePlugin.ShareSettingsActivity"
android:label="@string/device_menu_plugins"
android:parentActivityName="org.kde.kdeconnect.UserInterface.SettingsActivity" >
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="org.kde.kdeconnect.Plugins.SharePlugin.ShareSettingsActivity" />
</activity>
<receiver android:name="org.kde.kdeconnect.KdeConnectBroadcastReceiver" >
<intent-filter>
@@ -118,6 +140,8 @@
<activity
android:name="org.kde.kdeconnect.Plugins.FindMyPhonePlugin.FindMyPhoneActivity"
android:label="@string/findmyphone_title"
android:configChanges="orientation|screenSize"
android:excludeFromRecents="true"
android:launchMode="singleInstance">
</activity>

View File

@@ -3,18 +3,18 @@ buildscript {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.2.0'
classpath 'com.android.tools.build:gradle:2.3.0'
}
}
apply plugin: 'com.android.application'
android {
buildToolsVersion '23.0.3'
compileSdkVersion 23
buildToolsVersion '25.0.2'
compileSdkVersion 25
defaultConfig {
minSdkVersion 9
targetSdkVersion 22 //Bumping to 23 means we have to support the new permissions model
targetSdkVersion 22 //Bumping to >22 means we have to support the new permissions model
//multiDexEnabled true
//testInstrumentationRunner "com.android.test.runner.MultiDexTestRunner"
}
@@ -71,9 +71,9 @@ dependencies {
mavenCentral()
}
compile 'com.android.support:support-v4:23.4.0'
compile 'com.android.support:appcompat-v7:23.4.0'
compile 'com.android.support:design:23.4.0'
compile 'com.android.support:support-v4:25.1.1'
compile 'com.android.support:appcompat-v7:25.1.1'
compile 'com.android.support:design:25.1.1'
compile 'org.apache.sshd:sshd-core:0.8.0' //0.9 seems to fail on Android 6 and 1.+ requires java.nio.file, which doesn't exist in Android

Binary file not shown.

After

Width:  |  Height:  |  Size: 418 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 358 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 378 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 220 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 474 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 287 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 236 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 277 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 168 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 337 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 520 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 300 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 412 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 217 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 624 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 786 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 493 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 557 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 323 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 894 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 566 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 753 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 420 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -70,7 +70,7 @@
</LinearLayout>
<TextView
android:id="@+id/unpair_message"
android:id="@+id/not_reachable_message"
android:visibility="gone"
android:layout_width="match_parent"
android:drawableStart="@drawable/ic_error_outline_black_48dp"
@@ -82,6 +82,19 @@
android:textAppearance="?android:attr/textAppearanceMedium"
/>
<TextView
android:id="@+id/on_data_message"
android:visibility="gone"
android:layout_width="match_parent"
android:drawableStart="@drawable/ic_error_outline_black_48dp"
android:drawableLeft="@drawable/ic_error_outline_black_48dp"
android:drawablePadding="8dip"
android:layout_height="match_parent"
android:gravity="center_vertical"
android:text="@string/on_data_message"
android:textAppearance="?android:attr/textAppearanceMedium"
/>
<ListView
android:id="@+id/buttons_list"
android:layout_width="match_parent"

View File

@@ -20,11 +20,6 @@
android:id="@+id/no_players"
android:layout_gravity="center_horizontal" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/artImageView" />
<Spinner
android:layout_width="match_parent"
android:layout_height="wrap_content"

View File

@@ -62,7 +62,6 @@
<string name="received_file_text">Tap to open \'%1s\'</string>
<string name="sent_file_title">Unvióse\'l ficheru a %1s</string>
<string name="sent_file_text">%1s</string>
<string name="sent_file_failed_title">Fallu al unviar el ficheru %1s</string>
<string name="sent_file_failed_text">%1s</string>
<string name="tap_to_answer">Calca pa responder</string>
<string name="reconnect">Reconeutar</string>

View File

@@ -64,7 +64,6 @@
<string name="received_file_text">Kucni za otvaranje \'%1s\'</string>
<string name="sent_file_title">Poslana datoteka na %1s</string>
<string name="sent_file_text">%1s</string>
<string name="sent_file_failed_title">Neuspjelo slanje datoteke %1s</string>
<string name="sent_file_failed_text">%1s</string>
<string name="tap_to_answer">Kucni za odgovor</string>
<string name="reconnect">Ponovo uspostavi vezu</string>

View File

@@ -10,6 +10,8 @@
<string name="pref_plugin_clipboard_desc">Comparteix el contingut del porta-retalls</string>
<string name="pref_plugin_mousepad">Entrada remota</string>
<string name="pref_plugin_mousepad_desc">Usa el vostre telèfon o tauleta com un ratolí i un teclat</string>
<string name="pref_plugin_remotekeyboard">Rep les pulsacions de tecla remotes</string>
<string name="pref_plugin_remotekeyboard_desc">Rep els esdeveniments de pulsacions de tecla des de dispositius remots</string>
<string name="pref_plugin_mpris">Controls multimèdia</string>
<string name="pref_plugin_mpris_desc">Proporciona un comandament a distància pel reproductor multimèdia</string>
<string name="pref_plugin_runcommand">Executa una ordre</string>
@@ -30,6 +32,10 @@
<string name="no_permissions">Us caldrà concedir permís per accedir a les notificacions</string>
<string name="send_ping">Envia un ping</string>
<string name="open_mpris_controls">Control multimèdia</string>
<string name="remotekeyboard_editing_only_title">Fes servir les tecles remotes només en editar</string>
<string name="remotekeyboard_not_connected">No hi ha cap connexió activa amb el teclat remot, establiu-ne una al «kdeconnect»</string>
<string name="remotekeyboard_connected">La connexió amb el teclat remot està activa</string>
<string name="remotekeyboard_multiple_connections">Hi ha més d\'una connexió amb un teclat remot, seleccioneu el dispositiu per configurar-lo</string>
<string name="open_mousepad">Entrada remota</string>
<string name="mousepad_info">Moveu un dit per la pantalla per a moure el cursor del ratolí. Toqueu per un clic, i empreu dos/tres dits pels botons dret i mig. Empreu un toc llarg per arrossegar i deixar anar.</string>
<string name="mousepad_double_tap_settings_title">Estableix l\'acció de tocar amb dos dits</string>
@@ -79,13 +85,15 @@
<string name="incoming_file_title">Fitxer entrant des de %1s</string>
<string name="incoming_file_text">%1s</string>
<string name="outgoing_file_title">S\'està enviant el fitxer a %1s</string>
<string name="outgoing_files_title">S\'estan enviant fitxers a %1s</string>
<string name="outgoing_file_text">%1s</string>
<string name="outgoing_files_text">S\'ha enviat %1$d de %2$d fitxers</string>
<string name="received_file_title">Fitxer rebut des de %1s</string>
<string name="received_file_fail_title">Ha fallat en rebre el fitxer des de %1s</string>
<string name="received_file_text">Puntegeu per obrir «%1s»</string>
<string name="sent_file_title">Envia el fitxer a %1s</string>
<string name="sent_file_text">%1s</string>
<string name="sent_file_failed_title">Ha fallat en enviar el fitxer %1s</string>
<string name="sent_file_failed_title">Ha fallat en enviar el fitxer a %1s</string>
<string name="sent_file_failed_text">%1s</string>
<string name="tap_to_answer">Puntegeu per a respondre</string>
<string name="reconnect">Reconnecta</string>
@@ -132,6 +140,10 @@
<string name="custom_device_list">Afegeix dispositius per la IP</string>
<string name="share_notification_preference">Rebombori de les notificacions</string>
<string name="share_notification_preference_summary">Vibra i reprodueix un so en rebre un fitxer</string>
<string name="share_destination_customize">Personalitza el directori de destinació</string>
<string name="share_destination_customize_summary_disabled">Els fitxers rebuts apareixeran a Baixades</string>
<string name="share_destination_customize_summary_enabled">Els fitxers seran emmagatzemats al directori de a sota</string>
<string name="share_destination_folder_preference">Directori de destinació</string>
<string name="title_activity_notification_filter">Filtre per a les notificacions</string>
<string name="filter_apps_info">Les notificacions se sincronitzaran per a les aplicacions seleccionades.</string>
<string name="sftp_internal_storage">Emmagatzematge intern</string>
@@ -153,6 +165,7 @@
<string name="device_rename_confirm">Reanomena</string>
<string name="refresh">Refresca</string>
<string name="unreachable_description">Aquest dispositiu aparellat no és accessible. Assegureu-vos que està connectat a la mateixa xarxa.</string>
<string name="on_data_message">Sembla que esteu amb una connexió de dades mòbils. El KDE Connect només funciona amb xarxes locals.</string>
<string name="no_file_browser">No hi ha instal·lat cap explorador de fitxers.</string>
<string name="pref_plugin_telepathy">Envia un SMS</string>
<string name="pref_plugin_telepathy_desc">Envia missatges de text des de l\'escriptori</string>

View File

@@ -10,6 +10,8 @@
<string name="pref_plugin_clipboard_desc">Sdílet obsah schránky</string>
<string name="pref_plugin_mousepad">Vzdálený vstup</string>
<string name="pref_plugin_mousepad_desc">Používejte svůj telefon nebo tablet jako touchpad a klávesnici</string>
<string name="pref_plugin_remotekeyboard">Přijímat stisky kláves se vzdálených zařízení</string>
<string name="pref_plugin_remotekeyboard_desc">Přijímat události stisku kláves ze vzdálených zařízení</string>
<string name="pref_plugin_mpris">Ovládání multimédií</string>
<string name="pref_plugin_mpris_desc">Poskytuje dálkové ovládání přehrávačů médií</string>
<string name="pref_plugin_runcommand">Spustit příkaz</string>
@@ -20,7 +22,7 @@
<string name="pref_plugin_notifications_desc">Zpřístupněte si upozornění z jiných zařízení</string>
<string name="pref_plugin_receive_notifications">Přijímat oznámení</string>
<string name="pref_plugin_receive_notifications_desc">Přijímat oznámení z jiného zařízení a zobrazovat je v Androidu</string>
<string name="pref_plugin_sharereceiver">Sdílet s přijmnout</string>
<string name="pref_plugin_sharereceiver">Sdílet a přijmout</string>
<string name="pref_plugin_sharereceiver_desc">Sdílet soubory a odkazy mezi zařízeními</string>
<string name="plugin_not_available">Tato vlastnost není pro vaši verzi Androidu platná</string>
<string name="device_list_empty">Žádná zařízení</string>
@@ -30,6 +32,10 @@
<string name="no_permissions">Pro zpřístupnění upozornění potřebujete oprávnění</string>
<string name="send_ping">Poslat ping</string>
<string name="open_mpris_controls">Ovládání multimédií</string>
<string name="remotekeyboard_editing_only_title">Ovládat vzdálené klávesy při editaci</string>
<string name="remotekeyboard_not_connected">Není k dispozici žádné vzdálené připojení klávesnice. Nastavte nějaké pomocí kdeconnect</string>
<string name="remotekeyboard_connected">Vzdálené připojení klávesnice je aktivní</string>
<string name="remotekeyboard_multiple_connections">Je k dispozici více než jedno připojení klávesnice. Vyberte zařízení pro jeho nastavení.</string>
<string name="open_mousepad">Vzdálený vstup</string>
<string name="mousepad_info">Pohybujte prstem po obrazovce pro pohybování kurzorem myši. Ťukněte pro kliknutí a použijte dva/tři prsty jako pravé a prostřední tlačítko. Pro přetažení dlouze podržte.</string>
<string name="mousepad_double_tap_settings_title">Nastavit činnost pro ťuknutí dvěma prsty</string>
@@ -79,13 +85,15 @@
<string name="incoming_file_title">Příchozí soubor od %1s</string>
<string name="incoming_file_text">%1s</string>
<string name="outgoing_file_title">Odesílám soubor do %1s</string>
<string name="outgoing_files_title">Odesílám soubory do %1s</string>
<string name="outgoing_file_text">%1s</string>
<string name="outgoing_files_text">Odesláno %1$d ze %2$d souborů</string>
<string name="received_file_title">Přijat soubor od %1s</string>
<string name="received_file_fail_title">Selhalo přijímání souboru od %1s</string>
<string name="received_file_text">Ťukněte pro otevření \'%1s\'</string>
<string name="sent_file_title">Soubor byl odeslán do %1s</string>
<string name="sent_file_text">%1s</string>
<string name="sent_file_failed_title">Nelze odeslat soubor %1s</string>
<string name="sent_file_failed_title">Odesílání souborů na %1s selhalo</string>
<string name="sent_file_failed_text">%1s</string>
<string name="tap_to_answer">Ťukněte pro odpovězení</string>
<string name="reconnect">Znovu připojit</string>
@@ -132,6 +140,10 @@
<string name="custom_device_list">Přidat zařízení podle IP</string>
<string name="share_notification_preference">Hlasitá upozornění</string>
<string name="share_notification_preference_summary">Vibrovat a přehrát melodii při přijímání souboru</string>
<string name="share_destination_customize">Přizpůsobte si cílový adresář</string>
<string name="share_destination_customize_summary_disabled">Přijaté soubory se objeví v Downloads</string>
<string name="share_destination_customize_summary_enabled">Soubory budou ukládány v adresáři níže</string>
<string name="share_destination_folder_preference">Cílový adresář</string>
<string name="title_activity_notification_filter">Filtr upozornění</string>
<string name="filter_apps_info">Upozorňování mezi vybranými aplikacemi bude synchronizováno.</string>
<string name="sftp_internal_storage">Interní úložiště</string>
@@ -153,6 +165,7 @@
<string name="device_rename_confirm">Přejmenovat</string>
<string name="refresh">Obnovit</string>
<string name="unreachable_description">Toto spárované zařízení je nedosažitelné. Ujistěte se, že běží ve stejné síti.</string>
<string name="on_data_message">Vypadá to, že jste na mobilním internetovém připojení. KDE Connect funguje pouze na lokální síti.</string>
<string name="no_file_browser">Není nainstalován žádný prohlížeč souborů.</string>
<string name="pref_plugin_telepathy">Poslat SMS</string>
<string name="pref_plugin_telepathy_desc">Posílejte zprávy ze své pracovní plochy</string>

View File

@@ -10,9 +10,12 @@
<string name="pref_plugin_clipboard_desc">Del indholdet af udklipsholderen</string>
<string name="pref_plugin_mousepad">Eksternt input</string>
<string name="pref_plugin_mousepad_desc">Brug din telefon eller tablet som mus og tastatur</string>
<string name="pref_plugin_remotekeyboard">Modtag eksterne tastetryk</string>
<string name="pref_plugin_remotekeyboard_desc">Modtag tastetryk-hændelser fra eksterne enheder</string>
<string name="pref_plugin_mpris">Multimediekontroller</string>
<string name="pref_plugin_mpris_desc">Giver en fjernbetjening til din medieafspiller</string>
<string name="pref_plugin_runcommand">Kør kommando</string>
<string name="pref_plugin_runcommand_desc">Kør eksterne kommandoer fra din telefon eller tablet</string>
<string name="pref_plugin_ping">Ping</string>
<string name="pref_plugin_ping_desc">Send og modtag ping</string>
<string name="pref_plugin_notifications">Synk. af bekendtgørelser</string>
@@ -29,10 +32,16 @@
<string name="no_permissions">Du skal give tilladelse for at tilgå bekendtgørelser</string>
<string name="send_ping">Send ping</string>
<string name="open_mpris_controls">Multimediekontrol</string>
<string name="remotekeyboard_editing_only_title">Håndtér kun eksterne tastetryk under redigering</string>
<string name="remotekeyboard_not_connected">Der er ingen aktiv ekstern tastaturforbindelse. Opret en i kdeconnect</string>
<string name="remotekeyboard_connected">Ekstern tastaturforbindelse er aktiv</string>
<string name="remotekeyboard_multiple_connections">Der er mere end en ekstern tastaturforbindelse, vælg den enhed der skal konfigureres</string>
<string name="open_mousepad">Eksternt input</string>
<string name="mousepad_info">Bevæg en finger på skærmen for at flytte musemarkøren. Tap for at klikke og brug to/tre-fingre for højre og midterste museknap. Brug et langt tryk til at trække og slippe.</string>
<string name="mousepad_double_tap_settings_title">Angiv handling for tap med to fingre</string>
<string name="mousepad_triple_tap_settings_title">Angiv handling for tap med tre fingre</string>
<string name="mousepad_sensitivity_settings_title">Angiv følsomhed for touchpad</string>
<string name="mousepad_scroll_direction_title">Omvendt rulleretning</string>
<string-array name="mousepad_tap_entries">
<item>Højreklik</item>
<item>Midterklik</item>
@@ -40,12 +49,13 @@
</string-array>
<string name="mousepad_double_default">højre</string>
<string name="mousepad_triple_default">midter</string>
<string name="mousepad_sensitivity_default">standard</string>
<string-array name="mousepad_sensitivity_entries">
<item>Slowest</item>
<item>Above Slowest</item>
<item>Default</item>
<item>Above Default</item>
<item>Fastest</item>
<item>Mest langsom</item>
<item>Over mest langsom</item>
<item>Standard</item>
<item>Over standard</item>
<item>Hurtigste</item>
</string-array>
<string name="category_connected_devices">Forbundne enheder</string>
<string name="category_not_paired_devices">Tilgængelig enheder</string>
@@ -64,6 +74,10 @@
<string name="error_canceled_by_user">Annulleret af brugeren</string>
<string name="error_canceled_by_other_peer">Annulleret af modpart</string>
<string name="error_invalid_key">Ugyldige nøgle modtaget</string>
<string name="encryption_info_title">Krypteringsinfo</string>
<string name="encryption_info_msg_no_ssl">Den anden enhed bruger ikke en nylig version af KDE Connect, og bruger dermed den forældede krypteringsmetode.</string>
<string name="my_device_fingerprint">SHA1-fingeraftrykket for dit enhedscertifikat er:</string>
<string name="remote_device_fingerprint">SHA1-fingeraftrykket for det eksterne enhedscertifikat er:</string>
<string name="pair_requested">Anmodet om parring</string>
<string name="pairing_request_from">Parringsanmodning fra %1s</string>
<string name="received_url_title">Modtog link fra %1s</string>
@@ -77,7 +91,6 @@
<string name="received_file_text">Tap for at åbne \"%1s\"</string>
<string name="sent_file_title">Fil sendt til %1s</string>
<string name="sent_file_text">%1s</string>
<string name="sent_file_failed_title">Kunne ikke sende filen %1s</string>
<string name="sent_file_failed_text">%1s</string>
<string name="tap_to_answer">Tap for at svare</string>
<string name="reconnect">Forbind igen</string>
@@ -145,10 +158,15 @@
<string name="device_rename_confirm">Omdøb</string>
<string name="refresh">Genopfrisk</string>
<string name="unreachable_description">Denne parrede enhed kan ikke nås. Sørg for at den er forbundet til samme netværk som dig.</string>
<string name="on_data_message">Det lader til at du er på en mobil dataforbindelse. KDE Connect virker kun på lokale netværk.</string>
<string name="no_file_browser">Der er ingen filhåndtering installeret.</string>
<string name="pref_plugin_telepathy">Send SMS</string>
<string name="pref_plugin_telepathy_desc">Send SMS-beskeder fra din desktop</string>
<string name="plugin_not_supported">Dette plugin er ikke understøttet af enheden</string>
<string name="findmyphone_title">Find min telefon</string>
<string name="findmyphone_title_tablet">Find min tablet</string>
<string name="findmyphone_description">Ringer til denne enhed, så du kan finde den.</string>
<string name="findmyphone_found">Fundet</string>
<string name="open">Åbn</string>
<string name="close">Luk</string>
</resources>

View File

@@ -9,8 +9,9 @@
<string name="pref_plugin_clipboard">Abgleich der Zwischenablage</string>
<string name="pref_plugin_clipboard_desc">Inhalt der Zwischenablage freigeben</string>
<string name="pref_plugin_mousepad">Ferneingabe</string>
<string name="pref_plugin_mousepad_desc">Verwendet Ihr Handy als Tablett, Touchpad und Tastatur</string>
<string name="pref_plugin_mousepad_desc">Verwendet Ihr Handy als Tablet, Touchpad und Tastatur</string>
<string name="pref_plugin_mpris">Multimedia-Bedienung</string>
<string name="pref_plugin_mpris_desc">Eine Fernbedienung für Ihre Medienwiedergabe</string>
<string name="pref_plugin_runcommand">Befehl ausführen</string>
<string name="pref_plugin_runcommand_desc">Von Ihrem Telefon oder Tablett Befehle auf anderen Geräten ausführen</string>
<string name="pref_plugin_ping">Ping</string>
@@ -18,6 +19,7 @@
<string name="pref_plugin_notifications">Benachrichtigungs-Abgleich</string>
<string name="pref_plugin_notifications_desc">Zugriff auf Ihre Benachrichtigungen von anderen Geräten</string>
<string name="pref_plugin_receive_notifications">Benachrichtigungen empfangen</string>
<string name="pref_plugin_receive_notifications_desc">Empfangen und Anzeigen von Benachrichtigungen des anderen Geräts</string>
<string name="pref_plugin_sharereceiver">Veröffentlichen und Empfangen</string>
<string name="pref_plugin_sharereceiver_desc">Dateien und Adressen (URLs) zwischen Geräten teilen</string>
<string name="plugin_not_available">Diese Funktion ist in Ihrer Android-Version nicht verfügbar</string>
@@ -29,6 +31,7 @@
<string name="send_ping">Ping senden</string>
<string name="open_mpris_controls">Multimedia-Bedienung</string>
<string name="open_mousepad">Ferneingabe</string>
<string name="mousepad_info">Bewegen Sie einen Finger auf dem Bildschirm um den Maus-Zeiger zu verschieben. Tippen zum Klicken, mit zwei oder drei Fingern für rechten bzw. mittleren Mausknopf. Tippen und Halten für Ziehen und Ablegen.</string>
<string name="mousepad_double_tap_settings_title">Aktionsausführung bei Berührung mit zwei Fingern einstellen</string>
<string name="mousepad_triple_tap_settings_title">Aktionsausführung bei Berührung mit drei Fingern einstellen</string>
<string name="mousepad_sensitivity_settings_title">Empfindlichkeit des Touchpads einstellen</string>
@@ -43,9 +46,9 @@
<string name="mousepad_sensitivity_default">Standard</string>
<string-array name="mousepad_sensitivity_entries">
<item>Langsamste</item>
<item>Above Slowest</item>
<item>Langsam</item>
<item>Standard</item>
<item>Above Default</item>
<item>Schnell</item>
<item>Schnellste</item>
</string-array>
<string name="category_connected_devices">Verbundene Geräte</string>
@@ -66,17 +69,22 @@
<string name="error_canceled_by_other_peer">Abbruch durch Gegenstelle</string>
<string name="error_invalid_key">Ungültiger Schlüssel empfangen</string>
<string name="encryption_info_title">Verschlüsselungsinformationen</string>
<string name="encryption_info_msg_no_ssl">Das andere Gerät verwendet eine ältere Version von KDE-Connect, eine veraltete Verschlüsselungsmethode wird verwendet.</string>
<string name="my_device_fingerprint">Der SHA1-Fingerabdruck Ihres Gerätezertifikats lautet:</string>
<string name="remote_device_fingerprint">Der SHA1-Fingerabdruck des Gerätezertifikats der Gegenstelle lautet:</string>
<string name="pair_requested">Verbindung angefordert</string>
<string name="pairing_request_from">Verbindungsanfrage von %1s</string>
<string name="received_url_title">Verknüpfung von %1s erhalten</string>
<string name="received_url_text">Tippen um „%1s“ zu öffnen</string>
<string name="incoming_file_title">Eingehende Datei von %1s</string>
<string name="incoming_file_text">%1s</string>
<string name="outgoing_file_title">Datei wird an %1s gesendet</string>
<string name="outgoing_files_title">Datei wird an %1s gesendet</string>
<string name="outgoing_file_text">%1s</string>
<string name="outgoing_files_text">%1$d von %2$d Dateien gesendet</string>
<string name="received_file_title">Datei von %1s erhalten</string>
<string name="received_file_fail_title">Der Empfang der Datei %1s ist fehlgeschlagen</string>
<string name="received_file_text">Tippen um „%1s“ zu öffnen</string>
<string name="sent_file_title">Datei an %1s gesendet</string>
<string name="sent_file_text">%1s</string>
<string name="sent_file_failed_title">Das Senden der Datei an %1s ist fehlgeschlagen</string>
@@ -102,6 +110,7 @@
<string name="mpris_volume">Lautstärke</string>
<string name="mpris_settings">Multimedia-Einstellungen</string>
<string name="mpris_time_settings_title">Knöpfe Vorwärts/Rückwärts</string>
<string name="mpris_time_settings_summary">Sprungweite für Vorlauf/Rücklauf anpassen.</string>
<string-array name="mpris_time_entries">
<item>10 Sekunden</item>
<item>20 Sekunden</item>
@@ -122,9 +131,13 @@
<string name="custom_devices_settings">Benutzerdefinierte Geräteliste</string>
<string name="pair_device_action">Ein neues Gerät verbinden</string>
<string name="unpair_device_action">Verbindung %s trennen</string>
<string name="custom_device_list">Geräte nach IP hinzufügen</string>
<string name="custom_device_list">Geräte nach IP-Adresse hinzufügen</string>
<string name="share_notification_preference">Ausführliche Benachrichtigungen</string>
<string name="share_notification_preference_summary">Beim Empfang einer Datei vibrieren und einen Sound abspielen</string>
<string name="share_destination_customize">Zielverzeichnis anpassen</string>
<string name="share_destination_customize_summary_disabled">Empfangene Dateien werden in Downloads gespeichert</string>
<string name="share_destination_customize_summary_enabled">Dateien werden im folgenden Verzeichnis gespeichert</string>
<string name="share_destination_folder_preference">Zielverzeichnis</string>
<string name="title_activity_notification_filter">Benachrichtigungs-Filter</string>
<string name="filter_apps_info">Benachrichtigungen werden zwischen den ausgewählten Anwendungen abgeglichen.</string>
<string name="sftp_internal_storage">Interner Speicher</string>
@@ -133,17 +146,19 @@
<string name="sftp_sdcard">SD-Karte</string>
<string name="sftp_readonly">(Nur lesen)</string>
<string name="sftp_camera">Kamerabilder</string>
<string name="add_host">Rechner/IP hinzufügen</string>
<string name="add_host_hint">Rechnername oder IP</string>
<string name="add_host">Rechner/IP-Adresse hinzufügen</string>
<string name="add_host_hint">Rechnername oder IP-Adresse</string>
<string name="no_players_connected">Keine Medienspieler gefunden</string>
<string name="custom_dev_list_help">Benutzen Sie diese Funktion nur, wenn Ihr Gerät nicht automatisch erkannt wird. Geben hier Sie IP-Adresse oder Hostnamen ein und bestätigen Sie, um es zu der Liste hinzuzufügen. Tippen Sie ein bestehendes Gerät an, um es aus der Liste zu entfernen.</string>
<string name="mpris_player_on_device">%1$s auf %2$s</string>
<string name="send_files">Dateien senden</string>
<string name="pairing_title">KDE-Connect-Geräte</string>
<string name="pairing_description">Andere Geräte, auf denen KDE-Connect läuft im gleichen Netzwerk,sollte hier angezeigt werden.</string>
<string name="pairing_description">Andere Geräte im selben Netzwerk, auf denen KDE-Connect läuft, sollten hier angezeigt werden.</string>
<string name="device_paired">Gerät verbunden</string>
<string name="device_rename_title">Geräte umbenennen</string>
<string name="device_rename_confirm">Umbenennen</string>
<string name="refresh">Aktualisieren</string>
<string name="unreachable_description">Das verbundene Gerät ist nicht erreichbar. Stellen Sie sicher daß es mit demselben Netzwerk verbunden ist.</string>
<string name="no_file_browser">Es sind keine Dateiverwaltungsprogramme installiert.</string>
<string name="pref_plugin_telepathy">SMS senden</string>
<string name="pref_plugin_telepathy_desc">Text-Nachrichten von Ihrer Arbeitsfläche senden</string>

View File

@@ -5,15 +5,21 @@
<string name="pref_plugin_battery">Αναφορά μπαταρίας</string>
<string name="pref_plugin_battery_desc">Περιοδική αναφορά κατάστασης μπαταρίας</string>
<string name="pref_plugin_sftp">Αποκάλυψη συστήματος αρχείων</string>
<string name="pref_plugin_sftp_desc">Επιτρέπει την απομακρυσμένη περιήγηση του συστήματος αρχείων του κινητού</string>
<string name="pref_plugin_clipboard">Συγχρονισμός προχείρου</string>
<string name="pref_plugin_clipboard_desc">Διαμοιρασμός περιεχομένου προχείρου</string>
<string name="pref_plugin_mousepad">Απομακρυσμένη είσοδος στοιχείων</string>
<string name="pref_plugin_mousepad_desc">Χρήση του τηλεφώνου ή της ταμπλέτας σας ως επιφάνεια αφής και πληκτρολόγιο</string>
<string name="pref_plugin_mpris">Κονσόλα πολυμέσων</string>
<string name="pref_plugin_mpris_desc">Παρέχει ένα τηλεχειριστήριο για την αναπαραγωγή πολυμέσων</string>
<string name="pref_plugin_runcommand">Εκτέλεση εντολής</string>
<string name="pref_plugin_runcommand_desc">Εκτέλεση απομακρυσμένων εντολών από το τηλέφωνο ή την ταμπλέτα</string>
<string name="pref_plugin_ping">Ping</string>
<string name="pref_plugin_ping_desc">Αποστολή και λήψη pings</string>
<string name="pref_plugin_notifications">Συγχρονισμός ειδοποιήσεων</string>
<string name="pref_plugin_notifications_desc">Πρόσβαση σε ειδοποιήσεις από άλλες συσκευές</string>
<string name="pref_plugin_receive_notifications">Λήψη ειδοποιήσεων</string>
<string name="pref_plugin_receive_notifications_desc">Λήψη ειδοποιήσεων από την άλλη συσκευή και προβολή τους στο Android</string>
<string name="pref_plugin_sharereceiver">Διαμοιρασμός και λήψη</string>
<string name="pref_plugin_sharereceiver_desc">Διαμοιρασμός αρχείων και URL μεταξύ συσκευών</string>
<string name="plugin_not_available">Αυτή η λειτουργία δεν είναι διαθέσιμη στην τρέχουσα έκδοση του Android</string>
@@ -79,7 +85,6 @@
<string name="received_file_text">Χτυπήστε για άνοιγμα \'%1s\'</string>
<string name="sent_file_title">Εστάλη αρχείο στο %1s</string>
<string name="sent_file_text">%1s</string>
<string name="sent_file_failed_title">Αποτυχία αποστολής αρχείου %1s</string>
<string name="sent_file_failed_text">%1s</string>
<string name="tap_to_answer">Χτυπήστε για να απαντήσετε</string>
<string name="reconnect">Επανασύνδεση</string>
@@ -152,6 +157,8 @@
<string name="pref_plugin_telepathy_desc">Αποστολή μηνυμάτων κειμένου από τον υπολογιστή σας</string>
<string name="plugin_not_supported">Αυτό το πρόσθετο δεν υποστηρίζεται από τη συσκευή</string>
<string name="findmyphone_title">Αναζήτηση του κινητού μου</string>
<string name="findmyphone_title_tablet">Εύρεση της ταμπλέτας μου</string>
<string name="findmyphone_description">Καλεί αυτή τη συσκευή ώστε να την εντοπίσετε</string>
<string name="findmyphone_found">Βρέθηκε</string>
<string name="open">Άνοιγμα</string>
<string name="close">Κλείσιμο</string>

View File

@@ -10,6 +10,8 @@
<string name="pref_plugin_clipboard_desc">Share the clipboard content</string>
<string name="pref_plugin_mousepad">Remote input</string>
<string name="pref_plugin_mousepad_desc">Use your phone or tablet as a touchpad and keyboard</string>
<string name="pref_plugin_remotekeyboard">Receive remote keypresses</string>
<string name="pref_plugin_remotekeyboard_desc">Receive keypress events from remote devices</string>
<string name="pref_plugin_mpris">Multimedia controls</string>
<string name="pref_plugin_mpris_desc">Provides a remote control for your media player</string>
<string name="pref_plugin_runcommand">Run Command</string>
@@ -30,6 +32,10 @@
<string name="no_permissions">You need to grant permission to access notifications</string>
<string name="send_ping">Send ping</string>
<string name="open_mpris_controls">Multimedia control</string>
<string name="remotekeyboard_editing_only_title">Handle remote keys only when editing</string>
<string name="remotekeyboard_not_connected">There is no active remote keyboard connection, establish one in kdeconnect</string>
<string name="remotekeyboard_connected">Remote keyboard connection is active</string>
<string name="remotekeyboard_multiple_connections">There is more than one remote keyboard connection, select the device to configure</string>
<string name="open_mousepad">Remote input</string>
<string name="mousepad_info">Move a finger on the screen to move the mouse cursor. Tap for a click, and use two/three fingers for right and middle buttons. Use a long press to drag\'n drop.</string>
<string name="mousepad_double_tap_settings_title">Set two finger tap action</string>
@@ -79,13 +85,15 @@
<string name="incoming_file_title">Incoming file from %1s</string>
<string name="incoming_file_text">%1s</string>
<string name="outgoing_file_title">Sending file to %1s</string>
<string name="outgoing_files_title">Sending files to %1s</string>
<string name="outgoing_file_text">%1s</string>
<string name="outgoing_files_text">Sent %1$d out of %2$d files</string>
<string name="received_file_title">Received file from %1s</string>
<string name="received_file_fail_title">Failed receiving file from %1s</string>
<string name="received_file_text">Tap to open \'%1s\'</string>
<string name="sent_file_title">Sent file to %1s</string>
<string name="sent_file_text">%1s</string>
<string name="sent_file_failed_title">Failed to send file %1s</string>
<string name="sent_file_failed_title">Failed to send file to %1s</string>
<string name="sent_file_failed_text">%1s</string>
<string name="tap_to_answer">Tap to answer</string>
<string name="reconnect">Reconnect</string>
@@ -132,6 +140,10 @@
<string name="custom_device_list">Add devices by IP</string>
<string name="share_notification_preference">Noisy notifications</string>
<string name="share_notification_preference_summary">Vibrate and play a sound when receiving a file</string>
<string name="share_destination_customize">Customise destination directory</string>
<string name="share_destination_customize_summary_disabled">Received files will appear in Downloads</string>
<string name="share_destination_customize_summary_enabled">Files will be stored in the directory below</string>
<string name="share_destination_folder_preference">Destination directory</string>
<string name="title_activity_notification_filter">Notification filter</string>
<string name="filter_apps_info">Notifications will be synchronised for the selected apps.</string>
<string name="sftp_internal_storage">Internal storage</string>
@@ -153,6 +165,7 @@
<string name="device_rename_confirm">Rename</string>
<string name="refresh">Refresh</string>
<string name="unreachable_description">This paired device is not reachable. Make sure it is connected to your same network.</string>
<string name="on_data_message">It looks like you are on a mobile data connection. KDE Connect only works on local networks.</string>
<string name="no_file_browser">There are no file browsers installed.</string>
<string name="pref_plugin_telepathy">Send SMS</string>
<string name="pref_plugin_telepathy_desc">Send text messages from your desktop</string>

View File

@@ -10,6 +10,8 @@
<string name="pref_plugin_clipboard_desc">Compartir el contenido del portapapeles</string>
<string name="pref_plugin_mousepad">Entrada remota</string>
<string name="pref_plugin_mousepad_desc">Usar su teléfono o tableta como teclado y teclado táctil</string>
<string name="pref_plugin_remotekeyboard">Recibir pulsaciones de teclas remotas</string>
<string name="pref_plugin_remotekeyboard_desc">Reciba eventos de pulsación de teclas desde dispositivos remotos</string>
<string name="pref_plugin_mpris">Controles multimedia</string>
<string name="pref_plugin_mpris_desc">Proporciona un control remoto para su reproductor de medios</string>
<string name="pref_plugin_runcommand">Ejecutar orden</string>
@@ -30,6 +32,10 @@
<string name="no_permissions">Debe otorgar permiso para acceder a las notificaciones</string>
<string name="send_ping">Enviar ping</string>
<string name="open_mpris_controls">Control multimedia</string>
<string name="remotekeyboard_editing_only_title">Manejar teclas remotas solo al editar</string>
<string name="remotekeyboard_not_connected">No hay ninguna conexión remota de teclado activa, establezca una en kdeconnect</string>
<string name="remotekeyboard_connected">La conexión remota de teclado está activa</string>
<string name="remotekeyboard_multiple_connections">Hay más de una conexión remota de teclado, seleccione el dispositivo a configurar</string>
<string name="open_mousepad">Entrada remota</string>
<string name="mousepad_info">Mueva un dedo sobre la pantalla para mover el cursor del ratón. Pulse para ejecutar un clic y use dos/tres dedos para emular los botones derecho y central. Use una pulsación larga para arrastrar y soltar.</string>
<string name="mousepad_double_tap_settings_title">Establecer la acción al pulsar con dos dedos</string>
@@ -79,13 +85,15 @@
<string name="incoming_file_title">Archivo entrante desde %1s</string>
<string name="incoming_file_text">%1s</string>
<string name="outgoing_file_title">Enviando archivo a %1s</string>
<string name="outgoing_files_title">Enviando archivos a %1s</string>
<string name="outgoing_file_text">%1s</string>
<string name="outgoing_files_text">Enviados %1$d de %2$d archivos</string>
<string name="received_file_title">Archivo recibido desde %1s</string>
<string name="received_file_fail_title">Fallo recibiendo archivo desde %1s</string>
<string name="received_file_text">Pulse para abrir «%1s»</string>
<string name="sent_file_title">Archivo enviado a %1s</string>
<string name="sent_file_text">%1s</string>
<string name="sent_file_failed_title">Fallo al enviar el archivo %1s</string>
<string name="sent_file_failed_title">Fallo al enviar el archivo a %1s</string>
<string name="sent_file_failed_text">%1s</string>
<string name="tap_to_answer">Pulse para responder</string>
<string name="reconnect">Reconectar</string>
@@ -132,6 +140,10 @@
<string name="custom_device_list">Añadir dispositivos por IP</string>
<string name="share_notification_preference">Notificaciones ruidosas</string>
<string name="share_notification_preference_summary">Vibrar y reproducir un sonido cuando se reciba un archivo</string>
<string name="share_destination_customize">Personalizar directorio destino</string>
<string name="share_destination_customize_summary_disabled">Los archivos recibidos aparecerán en Descargas</string>
<string name="share_destination_customize_summary_enabled">Los archivos se almacenarán en el directorio indicado más abajo</string>
<string name="share_destination_folder_preference">Directorio destino</string>
<string name="title_activity_notification_filter">Filtro de notificaciones</string>
<string name="filter_apps_info">Las notificaciones se sincronizarán en las aplicaciones seleccionadas.</string>
<string name="sftp_internal_storage">Almacenamiento interno</string>
@@ -147,12 +159,13 @@
<string name="mpris_player_on_device">%1$s en %2$s</string>
<string name="send_files">Enviar archivos</string>
<string name="pairing_title">Dispositivos de KDE Connect</string>
<string name="pairing_description">Otros dispositivos ejecutando KDE Connect en su misma red deberían aparecer aquí.</string>
<string name="pairing_description">Cualquier otro dispositivo ejecutando KDE Connect en su misma red debería aparecer aquí.</string>
<string name="device_paired">Dispositivo vinculado</string>
<string name="device_rename_title">Renombrar dispositivo</string>
<string name="device_rename_confirm">Renombrar</string>
<string name="refresh">Actualizar</string>
<string name="unreachable_description">Este dispositivo vinculado no está disponible. Asegúrese que está conectado a su misma red.</string>
<string name="on_data_message">Parece que se encuentra en una conexión de datos móviles. KDE Connect solo funciona en redes locales.</string>
<string name="no_file_browser">No hay navegadores de archivos instalados.</string>
<string name="pref_plugin_telepathy">Enviar SMS</string>
<string name="pref_plugin_telepathy_desc">Enviar mensajes de texto desde el escritorio</string>

View File

@@ -79,13 +79,15 @@
<string name="incoming_file_title">Saabuv fail seadmest %1s</string>
<string name="incoming_file_text">%1s</string>
<string name="outgoing_file_title">Faili saatmine seadmesse %1s</string>
<string name="outgoing_files_title">Failide saatmine seadmesse %1s</string>
<string name="outgoing_file_text">%1s</string>
<string name="outgoing_files_text">Saadetud %1$d / %2$d faili</string>
<string name="received_file_title">Faili saamine seadmest %1s</string>
<string name="received_file_fail_title">Faili saamine seadmest %1s nurjus</string>
<string name="received_file_text">Koputa \"%1s\" avamiseks</string>
<string name="sent_file_title">Fail saadeti seadmesse %1s</string>
<string name="sent_file_text">%1s</string>
<string name="sent_file_failed_title">Faili %1s saatmine nurjus</string>
<string name="sent_file_failed_title">Faili saatmine seadmesse %1s nurjus</string>
<string name="sent_file_failed_text">%1s</string>
<string name="tap_to_answer">Koputa vastamiseks</string>
<string name="reconnect">Ühenda uuesti</string>
@@ -132,6 +134,10 @@
<string name="custom_device_list">Lisa seadmeid IP järgi</string>
<string name="share_notification_preference">Mürarikkad märguanded</string>
<string name="share_notification_preference_summary">Vibreerimine ja heli esitamine faili saamisel</string>
<string name="share_destination_customize">Sihtkataloogi kohandamine</string>
<string name="share_destination_customize_summary_disabled">Saadud failid salvestatakse kataloogi Allalaaditud</string>
<string name="share_destination_customize_summary_enabled">Failid salvestatakse allmääratud kataloogi</string>
<string name="share_destination_folder_preference">Sihtkataloog</string>
<string name="title_activity_notification_filter">Märguannete filter</string>
<string name="filter_apps_info">Valitud rakenduste märguanded sünkroonitakse</string>
<string name="sftp_internal_storage">Sisemine salvesti</string>

View File

@@ -5,15 +5,21 @@
<string name="pref_plugin_battery">Akkuraportti</string>
<string name="pref_plugin_battery_desc">Raportoi akun tila säännöllisesti</string>
<string name="pref_plugin_sftp">Tiedostojärjestelmän paljastaminen</string>
<string name="pref_plugin_sftp_desc">Mahdollistaa tämän laitteen tiedostojärjestelmän etäselaamisen</string>
<string name="pref_plugin_clipboard">Leikepöydän synkronointi</string>
<string name="pref_plugin_clipboard_desc">Jaa leikepöydän sisältö</string>
<string name="pref_plugin_mousepad">Kauko-ohjaus</string>
<string name="pref_plugin_mousepad_desc">Käytä puhelinta tai tablettia hiirenä ja näppäimistönä</string>
<string name="pref_plugin_mpris">Multimedian ohjaus</string>
<string name="pref_plugin_mpris_desc">Mahdollistaa mediasoittimen etäohjauksen</string>
<string name="pref_plugin_runcommand">Suorita komento</string>
<string name="pref_plugin_runcommand_desc">Suorita komentoja etänä puhelimelta tai tabletilta</string>
<string name="pref_plugin_ping">Tiedustelupaketti</string>
<string name="pref_plugin_ping_desc">Lähetä ja vastaanota tiedustelupaketteja</string>
<string name="pref_plugin_notifications">Ilmoitusten synkronointi</string>
<string name="pref_plugin_notifications_desc">Näe ilmoituksesi muissa laitteissa</string>
<string name="pref_plugin_receive_notifications">Vastaanota ilmoituksia</string>
<string name="pref_plugin_receive_notifications_desc">Vastaanota ilmoituksia toiselta laitteelta ja näytä ne Androidissa</string>
<string name="pref_plugin_sharereceiver">Jako ja vastaanottaminen</string>
<string name="pref_plugin_sharereceiver_desc">Jaa tiedostoja ja osoitteita laitteiden välillä</string>
<string name="plugin_not_available">Piirre ei ole käytettävissä Android-versiossasi</string>
@@ -28,6 +34,8 @@
<string name="mousepad_info">Liikuta hiiren osoitinta liikuttamalla sormeasi näytöllä. Napsauta napauttamalla yhdellä sormella, käytä oikeaa painiketta kahdella sormella ja keskipainiketta kolmella. Vedä ja pudota painamalla pitkään.</string>
<string name="mousepad_double_tap_settings_title">Aseta kahden sormen napautuksen toiminto</string>
<string name="mousepad_triple_tap_settings_title">Aseta kolmen sormen napautuksen toiminto</string>
<string name="mousepad_sensitivity_settings_title">Aseta kosketuslevyn herkkyys</string>
<string name="mousepad_scroll_direction_title">Käänteinen vierityssuunta</string>
<string-array name="mousepad_tap_entries">
<item>Oikea napsautus</item>
<item>Keskinapsautus</item>
@@ -35,12 +43,13 @@
</string-array>
<string name="mousepad_double_default">Oikea painike</string>
<string name="mousepad_triple_default">Keskipainike</string>
<string name="mousepad_sensitivity_default">oletus</string>
<string-array name="mousepad_sensitivity_entries">
<item>Slowest</item>
<item>Above Slowest</item>
<item>Default</item>
<item>Above Default</item>
<item>Fastest</item>
<item>Hitain</item>
<item>Hitainta suurempi</item>
<item>Oletus</item>
<item>Oletusta suurempi</item>
<item>Nopein</item>
</string-array>
<string name="category_connected_devices">Yhdistetyt laitteet</string>
<string name="category_not_paired_devices">Saatavilla olevat laitteet</string>
@@ -59,6 +68,10 @@
<string name="error_canceled_by_user">Käyttäjä perui</string>
<string name="error_canceled_by_other_peer">Vertaiskäyttäjä perui</string>
<string name="error_invalid_key">Vastaanotettiin väärä avain</string>
<string name="encryption_info_title">Salaustiedot</string>
<string name="encryption_info_msg_no_ssl">Toinen laite ei käytä KDE Connectin uudehkoa versiota, joten käytetään vanhaa salausmenetelmää.</string>
<string name="my_device_fingerprint">Laitteen varmenteen SHA1-sormenjälki on:</string>
<string name="remote_device_fingerprint">Etälaitteen varmenteen SHA1-sormenjälki on:</string>
<string name="pair_requested">Paripyyntö</string>
<string name="pairing_request_from">Paripyyntö laitteesta %1s</string>
<string name="received_url_title">Vastaanotettiin linkki lähettäjältä %1s</string>
@@ -72,7 +85,6 @@
<string name="received_file_text">Avaa ”%1s” napauttamalla</string>
<string name="sent_file_title">Tiedosto lähetetty laitteeseen %1s</string>
<string name="sent_file_text">%1s</string>
<string name="sent_file_failed_title">Tiedoston lähetys epäonnistui: %1s</string>
<string name="sent_file_failed_text">%1s</string>
<string name="tap_to_answer">Vastaa napauttamalla</string>
<string name="reconnect">Yhdistä uudelleen</string>
@@ -144,6 +156,9 @@
<string name="pref_plugin_telepathy">Lähetä tekstiviesti</string>
<string name="pref_plugin_telepathy_desc">Lähetä tekstiviestejä työpöydältäsi</string>
<string name="plugin_not_supported">Laite ei tue tätä liitännäistä</string>
<string name="findmyphone_title">Löydä puhelimeni</string>
<string name="findmyphone_title_tablet">Löydä tablettini</string>
<string name="findmyphone_description">Laittaa laitteen soimaan, jotta voit löytää sen.</string>
<string name="findmyphone_found">Löytyi</string>
<string name="open">Avaa</string>
<string name="close">Sulje</string>

View File

@@ -70,7 +70,6 @@
<string name="received_file_text">Appuyez pour ouvrir %1s</string>
<string name="sent_file_title">Fichier envoyé à %1s</string>
<string name="sent_file_text">%1s</string>
<string name="sent_file_failed_title">Impossible d\'envoyer le fichier %1s</string>
<string name="sent_file_failed_text">%1s</string>
<string name="tap_to_answer">Cliquer pour répondre</string>
<string name="reconnect">Reconnecter</string>

View File

@@ -72,7 +72,6 @@
<string name="received_file_text">Toque para abrir «%1s».</string>
<string name="sent_file_title">Enviouse o ficheiro a %1s</string>
<string name="sent_file_text">%1s</string>
<string name="sent_file_failed_title">Non foi posíbel enviar o ficheiro %1s</string>
<string name="sent_file_failed_text">%1s</string>
<string name="tap_to_answer">Toque para contestar</string>
<string name="reconnect">Conectar de novo</string>

View File

@@ -18,7 +18,7 @@
<string name="pref_plugin_sharereceiver_desc">שתף וקבל קבצים וכתובת אינטרנט בין התקנים</string>
<string name="plugin_not_available">אפשרות זו אינה זמינה בגרסת האנדרואיד שלך</string>
<string name="device_list_empty">אין התקנים</string>
<string name="ok">בסדר</string>
<string name="ok">אישור</string>
<string name="cancel">בטל</string>
<string name="open_settings">פתח הגדרות</string>
<string name="no_permissions">אתה צריך לתת הרשאות לגישה להתראות</string>
@@ -79,7 +79,6 @@
<string name="received_file_text">לחץ כדי לפתוח את %1s</string>
<string name="sent_file_title">הקובץ נשלח ל־%1s</string>
<string name="sent_file_text">%1s</string>
<string name="sent_file_failed_title">נכשל בשליחת הקובץ ל־%1s</string>
<string name="sent_file_failed_text">%1s</string>
<string name="tap_to_answer">לחץ כדי לענות</string>
<string name="reconnect">התחבר מחדש</string>

View File

@@ -10,6 +10,8 @@
<string name="pref_plugin_clipboard_desc">Condividi il contenuto degli appunti</string>
<string name="pref_plugin_mousepad">Impulso remoto</string>
<string name="pref_plugin_mousepad_desc">Usa il tuo telefono o il tablet come touchpad e tastiera</string>
<string name="pref_plugin_remotekeyboard">Ricevi pressioni dei tasti da remoto</string>
<string name="pref_plugin_remotekeyboard_desc">Ricevi eventi di pressione dei tasti da dispositivi remoti</string>
<string name="pref_plugin_mpris">Controlli multimediali</string>
<string name="pref_plugin_mpris_desc">Fornisce un controllo remoto per il tuo lettore multimediale</string>
<string name="pref_plugin_runcommand">Esegui comando</string>
@@ -30,6 +32,10 @@
<string name="no_permissions">Devi concedere i permessi per l\'accesso alle notifiche</string>
<string name="send_ping">Invia ping</string>
<string name="open_mpris_controls">Controllo multimediale</string>
<string name="remotekeyboard_editing_only_title">Gestisci i tasti remoti solo durante la modifica</string>
<string name="remotekeyboard_not_connected">Non c\'è una connessione attiva della tastiera remota, stabiliscine una da kdeconnect</string>
<string name="remotekeyboard_connected">La connessione della tastiera remota è attiva</string>
<string name="remotekeyboard_multiple_connections">Ci sono più connessioni di tastiere remote, seleziona il dispositivo da configurare</string>
<string name="open_mousepad">Impulso remoto</string>
<string name="mousepad_info">Muovi un dito sullo schermo per spostare il puntatore del mouse. Tocca per un clic e usa due/tre dita per i pulsanti destro e centrale. Utilizza una pressione lunga per trascinare e rilasciare.</string>
<string name="mousepad_double_tap_settings_title">Imposta azione per il tocco a due dita</string>
@@ -79,13 +85,15 @@
<string name="incoming_file_title">File in ingresso da %1s</string>
<string name="incoming_file_text">%1s</string>
<string name="outgoing_file_title">Invio file a %1s</string>
<string name="outgoing_files_title">Invio file a %1s</string>
<string name="outgoing_file_text">%1s</string>
<string name="outgoing_files_text">Inviati %1$d di %2$d file</string>
<string name="received_file_title">File ricevuto da %1s</string>
<string name="received_file_fail_title">Ricezione file da %1s non riuscita</string>
<string name="received_file_text">Tocca per aprire «%1s»</string>
<string name="sent_file_title">File inviato a %1s</string>
<string name="sent_file_text">%1s</string>
<string name="sent_file_failed_title">Invio del file %1s non riuscito</string>
<string name="sent_file_failed_title">Invio del file a %1s non riuscito</string>
<string name="sent_file_failed_text">%1s</string>
<string name="tap_to_answer">Tocca per rispondere</string>
<string name="reconnect">Riconnetti</string>
@@ -132,6 +140,10 @@
<string name="custom_device_list">Aggiungi dispositivi per IP</string>
<string name="share_notification_preference">Notifiche rumorose</string>
<string name="share_notification_preference_summary">Vibra e riproduci un suono alla ricezione di un file</string>
<string name="share_destination_customize">Personalizza la cartella di destinazione</string>
<string name="share_destination_customize_summary_disabled">I file ricevuti saranno visualizzati in Downloads</string>
<string name="share_destination_customize_summary_enabled">I file saranno memorizzati nella cartella seguente</string>
<string name="share_destination_folder_preference">Cartella di destinazione</string>
<string name="title_activity_notification_filter">Filtro delle notifiche</string>
<string name="filter_apps_info">Le notifiche saranno sincronizzate per le applicazioni selezionate.</string>
<string name="sftp_internal_storage">Archiviazione interna</string>
@@ -153,6 +165,7 @@
<string name="device_rename_confirm">Rinomina</string>
<string name="refresh">Aggiorna</string>
<string name="unreachable_description">Questo dispositivo associato non è raggiungibile. Assicurati che sia connesso alla tua stessa rete.</string>
<string name="on_data_message">Sembra che tu stia utilizzando una connessione dati mobile. KDE Connect funziona solo su reti locali.</string>
<string name="no_file_browser">Non ci sono navigatori di file installati.</string>
<string name="pref_plugin_telepathy">Invia SMS</string>
<string name="pref_plugin_telepathy_desc">Invia messaggi di testo dal tuo desktop</string>

View File

@@ -5,15 +5,21 @@
<string name="pref_plugin_battery">배터리 보고</string>
<string name="pref_plugin_battery_desc">주기적으로 배터리 상태 보고</string>
<string name="pref_plugin_sftp">파일 시스템 보기</string>
<string name="pref_plugin_sftp_desc">원격으로 이 장치의 파일 시스템 보기</string>
<string name="pref_plugin_clipboard">클립보드 동기화</string>
<string name="pref_plugin_clipboard_desc">클립보드 내용 동기화</string>
<string name="pref_plugin_mousepad">원격 입력</string>
<string name="pref_plugin_mousepad_desc">내 휴대폰이나 태블릿을 터치패드와 키보드로 사용하기</string>
<string name="pref_plugin_mpris">멀티미디어 제어</string>
<string name="pref_plugin_mpris_desc">내 미디어 재생기 원격 제어</string>
<string name="pref_plugin_runcommand">명령 실행</string>
<string name="pref_plugin_runcommand_desc">내 휴대폰이나 태블릿에서 원격 명령 실행</string>
<string name="pref_plugin_ping"></string>
<string name="pref_plugin_ping_desc">핑 보내고 받기</string>
<string name="pref_plugin_notifications">알림 동기화</string>
<string name="pref_plugin_notifications_desc">다른 장치에서 알림 보기</string>
<string name="pref_plugin_receive_notifications">알림 받기</string>
<string name="pref_plugin_receive_notifications_desc">다른 장치의 알림을 받아서 안드로이드 알림에 표시</string>
<string name="pref_plugin_sharereceiver">공유하고 받기</string>
<string name="pref_plugin_sharereceiver_desc">장치끼리 파일과 URL 공유</string>
<string name="plugin_not_available">현재 안드로이드 버전에서 사용할 수 없습니다</string>
@@ -28,6 +34,8 @@
<string name="mousepad_info">화면에서 손가락을 움직이면 마우스 커서를 움직입니다. 화면을 누르면 왼쪽 단추를 누르고, 두 손가락과 세 손가락으로 누르면 오른쪽/가운데 단추를 누릅니다. 드래그 앤 드롭을 사용하려면 길게 누르십시오.</string>
<string name="mousepad_double_tap_settings_title">두 손가락으로 눌렀을 때 동작 설정</string>
<string name="mousepad_triple_tap_settings_title">세 손가락으로 눌렀을 때 동작 설정</string>
<string name="mousepad_sensitivity_settings_title">터치패드 감도 설정</string>
<string name="mousepad_scroll_direction_title">스크롤 방향 뒤집기</string>
<string-array name="mousepad_tap_entries">
<item>오른쪽 단추 누름</item>
<item>가운데 단추 누름</item>
@@ -35,12 +43,13 @@
</string-array>
<string name="mousepad_double_default">오른쪽</string>
<string name="mousepad_triple_default">가운데</string>
<string name="mousepad_sensitivity_default">기본값</string>
<string-array name="mousepad_sensitivity_entries">
<item>Slowest</item>
<item>Above Slowest</item>
<item>Default</item>
<item>Above Default</item>
<item>Fastest</item>
<item>느리게</item>
<item>느리게 이상</item>
<item>기본값</item>
<item>기본값 이상</item>
<item>빠르게</item>
</string-array>
<string name="category_connected_devices">연결된 장치</string>
<string name="category_not_paired_devices">사용 가능한 장치</string>
@@ -49,6 +58,7 @@
<string name="device_menu_plugins">플러그인 설정</string>
<string name="device_menu_unpair">연결 해제</string>
<string name="device_not_reachable">연결된 장치에 도달할 수 없음</string>
<string name="pair_new_device">새 장치 연결</string>
<string name="unknown_device">알 수 없는 장치</string>
<string name="error_not_reachable">장치에 접근할 수 없음</string>
<string name="error_already_requested">연결이 이미 요청됨</string>
@@ -58,6 +68,10 @@
<string name="error_canceled_by_user">사용자가 취소함</string>
<string name="error_canceled_by_other_peer">다른 쪽에서 취소함</string>
<string name="error_invalid_key">잘못된 키 받음</string>
<string name="encryption_info_title">암호화 정보</string>
<string name="encryption_info_msg_no_ssl">다른 장치에서 KDE Connect의 최근 버전을 실행하고 있지 않아서 레거시 암호화를 사용합니다.</string>
<string name="my_device_fingerprint">내 장치 인증서의 SHA1 지문:</string>
<string name="remote_device_fingerprint">원격 장치 인증서의 SHA1 지문:</string>
<string name="pair_requested">연결 요청됨</string>
<string name="pairing_request_from">%1s에서 연결 요청</string>
<string name="received_url_title">%1s에서 링크 받음</string>
@@ -65,13 +79,15 @@
<string name="incoming_file_title">%1s에서 파일 보냄</string>
<string name="incoming_file_text">%1s</string>
<string name="outgoing_file_title">%1s(으)로 파일 보내는 중</string>
<string name="outgoing_files_title">%1s(으)로 파일 보내는 중</string>
<string name="outgoing_file_text">%1s</string>
<string name="outgoing_files_text">파일 %2$d개 중 %1$d개 보냄</string>
<string name="received_file_title">%1s에서 파일 받음</string>
<string name="received_file_fail_title">%1s에서 파일 받기 실패</string>
<string name="received_file_text">\'%1s\'을(를) 열려면 누르십시오</string>
<string name="sent_file_title">%1s(으)로 파일 보냄</string>
<string name="sent_file_text">%1s</string>
<string name="sent_file_failed_title">파일 %1s을(를) 보낼 수 없음</string>
<string name="sent_file_failed_title">파일 %1s(으)로 보낼 수 없음</string>
<string name="sent_file_failed_text">%1s</string>
<string name="tap_to_answer">눌러서 응답하기</string>
<string name="reconnect">다시 연결</string>
@@ -118,6 +134,10 @@
<string name="custom_device_list">IP로 장치 추가</string>
<string name="share_notification_preference">시끄러운 알림</string>
<string name="share_notification_preference_summary">파일을 받았을 때 진동과 소리로 알림</string>
<string name="share_destination_customize">대상 디렉터리 사용자 정의</string>
<string name="share_destination_customize_summary_disabled">받은 파일을 다운로드 디렉터리에 저장함</string>
<string name="share_destination_customize_summary_enabled">받은 파일을 아래 디렉터리에 저장함</string>
<string name="share_destination_folder_preference">대상 디렉터리</string>
<string name="title_activity_notification_filter">알림 필터</string>
<string name="filter_apps_info">선택한 앱의 알림을 동기화합니다.</string>
<string name="sftp_internal_storage">내부 저장소</string>
@@ -143,6 +163,9 @@
<string name="pref_plugin_telepathy">SMS 보내기</string>
<string name="pref_plugin_telepathy_desc">데스크톱에서 문자 메시지 보내기</string>
<string name="plugin_not_supported">장치에서 이 플러그인을 지원하지 않습니다</string>
<string name="findmyphone_title">내 휴대폰 찾기</string>
<string name="findmyphone_title_tablet">내 태블릿 찾기</string>
<string name="findmyphone_description">이 장치에서 소리를 울려서 찾는 데 도움을 줍니다</string>
<string name="findmyphone_found">찾았음</string>
<string name="open">열기</string>
<string name="close">닫기</string>

View File

@@ -10,6 +10,8 @@
<string name="pref_plugin_clipboard_desc">De inhoud van het klembord delen</string>
<string name="pref_plugin_mousepad">Invoer op afstand</string>
<string name="pref_plugin_mousepad_desc">Uw telefoon of tablet gebruiken als een touchpad en toetsenbord</string>
<string name="pref_plugin_remotekeyboard">Toetsaanslagen van afstand ontvangen</string>
<string name="pref_plugin_remotekeyboard_desc">Toetsaanslaggebeurtenissen ontvangen van externe apparaten</string>
<string name="pref_plugin_mpris">Bediening van multimedia</string>
<string name="pref_plugin_mpris_desc">Biedt een afstandsbediening voor uw mediaspeler</string>
<string name="pref_plugin_runcommand">Commando uitvoeren</string>
@@ -30,6 +32,10 @@
<string name="no_permissions">U moet toestemming geven voor toegang tot meldingen</string>
<string name="send_ping">Ping verzenden</string>
<string name="open_mpris_controls">Bediening van multimedia</string>
<string name="remotekeyboard_editing_only_title">Behandel toetsen op afstand alleen bij bewerken</string>
<string name="remotekeyboard_not_connected">Er is geen actieve verbinding met een toetsenbord op afstand, maak er een in kdeconnect</string>
<string name="remotekeyboard_connected">Verbinding met toetsenbord op afstand is actief</string>
<string name="remotekeyboard_multiple_connections">Er is meer dan een verbinding met een toetsenbord op afstand, selecteer het te configureren apparaat</string>
<string name="open_mousepad">Invoer op afstand</string>
<string name="mousepad_info">Veeg met een vinger op het scherm om de muiscursor te verplaatsen. Tik om te klikken en gebruik twee/drie vingers voor rechter en middelste knop. Druk lang voor slepen en loslaten.</string>
<string name="mousepad_double_tap_settings_title">Tikactie met twee vingers instellen</string>
@@ -61,7 +67,7 @@
<string name="pair_new_device">Nieuw apparaat paren</string>
<string name="unknown_device">Onbekend apparaat</string>
<string name="error_not_reachable">Apparaat niet bereikbaar</string>
<string name="error_already_requested">Paar maken is al gevraagd</string>
<string name="error_already_requested">Paarvorming is al gevraagd</string>
<string name="error_already_paired">Apparaat is al gepaard</string>
<string name="error_could_not_send_package">Kon pakket niet verzenden</string>
<string name="error_timed_out">Tijdslimiet overschreden</string>
@@ -79,13 +85,15 @@
<string name="incoming_file_title">Inkomend bestand van %1s</string>
<string name="incoming_file_text">%1s</string>
<string name="outgoing_file_title">Bezig bestand te verzenden naar %1s</string>
<string name="outgoing_files_title">Bestanden verzenden naar %1s</string>
<string name="outgoing_file_text">%1s</string>
<string name="outgoing_files_text">Verzonden %1$d van %2$d bestanden</string>
<string name="received_file_title">Bestand ontvangen van %1s</string>
<string name="received_file_fail_title">Bestand ontvangen van %1s is mislukt</string>
<string name="received_file_text">Tap om \'%1s\' te openen</string>
<string name="sent_file_title">Bestand verzonden naar %1s</string>
<string name="sent_file_text">%1s</string>
<string name="sent_file_failed_title">Verzenden van bestand %1s is mislukt</string>
<string name="sent_file_failed_title">Verzenden van bestanden naar %1s is mislukt</string>
<string name="sent_file_failed_text">%1s</string>
<string name="tap_to_answer">Tap om te antwoorden</string>
<string name="reconnect">Opnieuw verbinden</string>
@@ -132,6 +140,10 @@
<string name="custom_device_list">Voeg apparaten toe per IP-adres</string>
<string name="share_notification_preference">Luidruchtige meldingen</string>
<string name="share_notification_preference_summary">Vibreer en speel een geluidje bij ontvangen van een bestand</string>
<string name="share_destination_customize">Pas bestemmingsmap aan</string>
<string name="share_destination_customize_summary_disabled">Ontvangen bestanden zullen in Downloads verschijnen</string>
<string name="share_destination_customize_summary_enabled">Bestanden zullen opgeslagen worden in de onderstaande map</string>
<string name="share_destination_folder_preference">Bestemmingsmap</string>
<string name="title_activity_notification_filter">Filter voor meldingen</string>
<string name="filter_apps_info">Meldingen zullen gesynchroniseerd worden voor de geselecteerde apps.</string>
<string name="sftp_internal_storage">Interne opslag</string>
@@ -153,6 +165,7 @@
<string name="device_rename_confirm">Hernoemen</string>
<string name="refresh">Verversen</string>
<string name="unreachable_description">Dit gepaarde apparaat is niet bereikbaar. Ga na dat het is verbonden met uw zelfde netwerk.</string>
<string name="on_data_message">Het lijkt of op een mobiele gegevensverbinding zit. KDE Connect werkt alleen op locale netwerken.</string>
<string name="no_file_browser">Er zijn geen bestandsbrowsers geïnstalleerd.</string>
<string name="pref_plugin_telepathy">SMS verzenden</string>
<string name="pref_plugin_telepathy_desc">Stuur tekstberichten van uw bureaublad</string>

165
res/values-nn/strings.xml Normal file
View File

@@ -0,0 +1,165 @@
<?xml version='1.0' encoding='utf-8'?>
<resources>
<string name="pref_plugin_telephony">Telefonvarsling</string>
<string name="pref_plugin_telephony_desc">Send varsling ved SMS og oppringing</string>
<string name="pref_plugin_battery">Batterirapport</string>
<string name="pref_plugin_battery_desc">Meld regelmessig frå om batteristatusen</string>
<string name="pref_plugin_sftp">Vis filsystem</string>
<string name="pref_plugin_sftp_desc">Tillat lesing av filsystemet frå datamaskina</string>
<string name="pref_plugin_clipboard">Synkroniser utklippstavle</string>
<string name="pref_plugin_clipboard_desc">Del innhaldet på utklippstavla</string>
<string name="pref_plugin_mousepad">Fjernstyring</string>
<string name="pref_plugin_mousepad_desc">Bruk telefonen eller nettbrettet som styrepute og tastatur</string>
<string name="pref_plugin_mpris">Mediekontrollar</string>
<string name="pref_plugin_mpris_desc">Gjev fjernkontroll til mediespelarar</string>
<string name="pref_plugin_runcommand">Køyr kommando</string>
<string name="pref_plugin_runcommand_desc">Utløys fjernkommandoar frå telefonen eller nettbrettet</string>
<string name="pref_plugin_ping">Ping</string>
<string name="pref_plugin_ping_desc">Send og ta imot ping-signal</string>
<string name="pref_plugin_notifications">Varslingssynkronisering</string>
<string name="pref_plugin_notifications_desc">Få tilgang til varslingar frå andre einingar</string>
<string name="pref_plugin_receive_notifications">Få varslingar</string>
<string name="pref_plugin_receive_notifications_desc">Få varslingar frå den andre eininga og vis dei i Android</string>
<string name="pref_plugin_sharereceiver">Del og ta imot</string>
<string name="pref_plugin_sharereceiver_desc">Del filer og nettadresser mellom einingar</string>
<string name="plugin_not_available">Denne funksjonen er ikkje tilgjengeleg i din Android-versjon</string>
<string name="device_list_empty">Ingen einingar</string>
<string name="ok">OK</string>
<string name="cancel">Avbryt</string>
<string name="open_settings">Opna innstillingar</string>
<string name="no_permissions">Du må gje tilgang til lesing av varslingar</string>
<string name="send_ping">Send pingsignal</string>
<string name="open_mpris_controls">Mediekontroll</string>
<string name="open_mousepad">Fjernstyring</string>
<string name="mousepad_info">Dra ein finger over skjermen for å flytta peikaren på datamaskina. Trykk for å klikka, og bruk to eller tre fingrar for høvesvis høgre- og midtknappen. Trykk og hald for å dra og sleppa.</string>
<string name="mousepad_double_tap_settings_title">Vel handling for tofingertrykk</string>
<string name="mousepad_triple_tap_settings_title">Vel handling for trefingertrykk</string>
<string name="mousepad_sensitivity_settings_title">Vel følsemd for styrepute</string>
<string name="mousepad_scroll_direction_title">Omvend rulleretning</string>
<string-array name="mousepad_tap_entries">
<item>Høgreklikk</item>
<item>Midtklikk</item>
<item>Ingenting</item>
</string-array>
<string name="mousepad_double_default">høgre</string>
<string name="mousepad_triple_default">midt</string>
<string name="mousepad_sensitivity_default">standard</string>
<string-array name="mousepad_sensitivity_entries">
<item>Saktast</item>
<item>Raskare enn saktast</item>
<item>Standard</item>
<item>Raskare enn standard</item>
<item>Raskast</item>
</string-array>
<string name="category_connected_devices">Tilkopla einingar</string>
<string name="category_not_paired_devices">Tilgjengelege einingar</string>
<string name="category_remembered_devices">Hugs einingar</string>
<string name="plugins_failed_to_load">Klarte ikkje lasta programtillegg (trykk for meir informasjon):</string>
<string name="device_menu_plugins">Innstillingar for programtillegg</string>
<string name="device_menu_unpair">Løys paring</string>
<string name="device_not_reachable">Får ikkje kontakt med para eining</string>
<string name="pair_new_device">Par ny eining</string>
<string name="unknown_device">Ukjend eining</string>
<string name="error_not_reachable">Får ikkje kontakt med eininga</string>
<string name="error_already_requested">Paringsførespurnad er alt send</string>
<string name="error_already_paired">Eininga er alt para</string>
<string name="error_could_not_send_package">Klarte ikkje senda pakke</string>
<string name="error_timed_out">Tidsavbrot</string>
<string name="error_canceled_by_user">Avbroten av brukar</string>
<string name="error_canceled_by_other_peer">Avbroten av den andre eininga</string>
<string name="error_invalid_key">Fekk ugyldig nøkkel</string>
<string name="encryption_info_title">Krypteringsinfo</string>
<string name="encryption_info_msg_no_ssl">Den andre eininga brukar ein gammal versjon av KDE Connect, med ein utdatert krypteringsmetode.</string>
<string name="my_device_fingerprint">SHA-fingeravtrykk av einingssertifikatet er:</string>
<string name="remote_device_fingerprint">SHA-fingeravtrykk av fjerneiningssertifikatet er:</string>
<string name="pair_requested">Paringsførespurnad</string>
<string name="pairing_request_from">Paringsførespurnad frå %1s</string>
<string name="received_url_title">Fekk lenkje frå %1s</string>
<string name="received_url_text">Trykk for å opna «%1s»</string>
<string name="incoming_file_title">Får fil frå %1s</string>
<string name="incoming_file_text">%1s</string>
<string name="outgoing_file_title">Sender fil til %1s</string>
<string name="outgoing_file_text">%1s</string>
<string name="received_file_title">Fekk fil frå %1s</string>
<string name="received_file_fail_title">Klarte ikkje ta imot fil frå %1s</string>
<string name="received_file_text">Trykk for å opna «%1s»</string>
<string name="sent_file_title">Send fil til %1s</string>
<string name="sent_file_text">%1s</string>
<string name="sent_file_failed_text">%1s</string>
<string name="tap_to_answer">Trykk for å svara</string>
<string name="reconnect">Kopla til på nytt</string>
<string name="right_click">Send høgreklikk</string>
<string name="middle_click">Send midtklikk</string>
<string name="show_keyboard">Vis tastatur</string>
<string name="device_not_paired">Eininga er ikkje para</string>
<string name="request_pairing">Be om paring</string>
<string name="pairing_accept">Godta</string>
<string name="pairing_reject">Avvis</string>
<string name="device">Eining</string>
<string name="pair_device">Par ny eining</string>
<string name="remote_control">Fjernstyring</string>
<string name="settings">Innstillingar for KDE Connect</string>
<string name="mpris_play">Spel</string>
<string name="mpris_previous">Førre</string>
<string name="mpris_rew">Spol tilbake</string>
<string name="mpris_ff">Spol fram</string>
<string name="mpris_next">Neste</string>
<string name="mpris_volume">Lydstyrke</string>
<string name="mpris_settings">Medieinnstillingar</string>
<string name="mpris_time_settings_title">Spoleknappar</string>
<string name="mpris_time_settings_summary">Juster tida for spoling ved trykking.</string>
<string-array name="mpris_time_entries">
<item>10 sekund</item>
<item>20 sekund</item>
<item>30 sekund</item>
<item>1 minutt</item>
<item>2 minutt</item>
</string-array>
<string name="share_to">Del til </string>
<string name="protocol_version_older">Denne eininga brukar ein gammal protokollversjon</string>
<string name="protocol_version_newer">Denne eininga brukar ein nyare protokollversjon</string>
<string name="general_settings">Generelle innstillingar</string>
<string name="plugin_settings">Innstillingar</string>
<string name="plugin_settings_with_name">%s-innstillingar</string>
<string name="device_name">Einingsnamn</string>
<string name="device_name_preference_summary">%s</string>
<string name="invalid_device_name">Ugyldig einingsnamn</string>
<string name="shareplugin_text_saved">Fekk tekst, som vart lagra på utklippstavla</string>
<string name="custom_devices_settings">Tilpassa einingsliste</string>
<string name="pair_device_action">Par ny eining</string>
<string name="unpair_device_action">Løys paring for %s</string>
<string name="custom_device_list">Legg til eining basert på IP</string>
<string name="share_notification_preference">Lydvarsling</string>
<string name="share_notification_preference_summary">Vibrer og spel ein lyd ved mottak av fil</string>
<string name="title_activity_notification_filter">Varslingsfilter</string>
<string name="filter_apps_info">Varslingar vert synkroniserte for dei valde appane.</string>
<string name="sftp_internal_storage">Intern lagring</string>
<string name="sftp_all_files">Alle filer</string>
<string name="sftp_sdcard_num">SD-kort %d</string>
<string name="sftp_sdcard">SD-kort</string>
<string name="sftp_readonly">(skriveverna)</string>
<string name="sftp_camera">Kamerabilete</string>
<string name="add_host">Legg til vert/IP</string>
<string name="add_host_hint">Vertsnamn/IP-adresse</string>
<string name="no_players_connected">Fann ingen spelarar</string>
<string name="custom_dev_list_help">Bruk berre dette valet viss eininga ikkje vert kjend att automatisk. Skriv inn IP-adressa eller vertsnamnet nedanfor, og trykk på knappen for å leggja eininga til oversikta. Trykk på element i oversikta for å fjerna dei.</string>
<string name="mpris_player_on_device">%1$s på %2$s</string>
<string name="send_files">Send filer</string>
<string name="pairing_title">KDE Connect-einingar</string>
<string name="pairing_description">Andre einingar i nettverket som køyrer KDE Connect vil dukka opp her.</string>
<string name="device_paired">Eininga er para</string>
<string name="device_rename_title">Endra namn på eining</string>
<string name="device_rename_confirm">Endra namn</string>
<string name="refresh">Oppdater</string>
<string name="unreachable_description">Får ikkje kontakt med den para eininga. Sjå til at ho er kopla til same nettverk.</string>
<string name="no_file_browser">Ingen filhandsamarar er installerte.</string>
<string name="pref_plugin_telepathy">Send SMS</string>
<string name="pref_plugin_telepathy_desc">Send tekstmeldingar frå datamaskina</string>
<string name="plugin_not_supported">Dette tillegget er ikkje støtta av eininga</string>
<string name="findmyphone_title">Finn telefonen min</string>
<string name="findmyphone_title_tablet">Finn nettbrettet mitt</string>
<string name="findmyphone_description">Ring til eininga, slik at du kan finna ho</string>
<string name="findmyphone_found">Fann</string>
<string name="open">Opna</string>
<string name="close">Lukk</string>
</resources>

View File

@@ -10,6 +10,8 @@
<string name="pref_plugin_clipboard_desc">Udostępnij zawartość schowka</string>
<string name="pref_plugin_mousepad">Zdalne sterowanie</string>
<string name="pref_plugin_mousepad_desc">Użyj swojego telefonu lub tabletu jako myszy i klawiatury</string>
<string name="pref_plugin_remotekeyboard">Odbieraj zdalne naciśnięcia klawiszy</string>
<string name="pref_plugin_remotekeyboard_desc">Odbieraj naciśnięcia klawiszy od urządzeń zdalnych</string>
<string name="pref_plugin_mpris">Sterowanie multimediami</string>
<string name="pref_plugin_mpris_desc">Zapewnia zdalne sterowanie twoim odtwarzaczem multimedialnym</string>
<string name="pref_plugin_runcommand">Wykonaj polecenie</string>
@@ -30,6 +32,10 @@
<string name="no_permissions">Musisz przydzielić uprawnienia, aby uzyskać dostęp do powiadomień</string>
<string name="send_ping">Wyślij ping</string>
<string name="open_mpris_controls">Sterowanie multimediami</string>
<string name="remotekeyboard_editing_only_title">Obsługuj zdalne naciśnięcia klawiszy tylko podczas edycji</string>
<string name="remotekeyboard_not_connected">Nie istnieje połączenie zdalnej klawiatury, nawiąż takie połączenie w kdeconnect</string>
<string name="remotekeyboard_connected">Połączenie zdalnej klawiatury jest nawiązane</string>
<string name="remotekeyboard_multiple_connections">Nawiązano więcej niż jedno połączenie zdalnej klawiatury, wybierz urządzenie do ustawienia</string>
<string name="open_mousepad">Zdalne sterowanie</string>
<string name="mousepad_info">Przesuń palcem po ekranie, aby przesunąć wskaźnik myszy. Stuknij, aby wywołać naciśniecie lewym przyciskiem myszy i użyj dwóch/trzech palców, aby wywołać naciśniecie prawym i środkowym przyciskiem myszy. Przyciśnij na dłużej, aby przeciągnąć i upuścić.</string>
<string name="mousepad_double_tap_settings_title">Ustaw działanie po dwukrotnym stuknięciu palcem</string>
@@ -79,13 +85,15 @@
<string name="incoming_file_title">Plik przychodzący od %1s</string>
<string name="incoming_file_text">%1s</string>
<string name="outgoing_file_title">Wysyłanie pliku do %1s</string>
<string name="outgoing_files_title">Wysyłanie pliku do %1s</string>
<string name="outgoing_file_text">%1s</string>
<string name="outgoing_files_text">Wysłano %1$d z %2$d plików</string>
<string name="received_file_title">Odebrano plik od %1s</string>
<string name="received_file_fail_title">Nieudane odbieranie pliku z %1s</string>
<string name="received_file_text">Znacznik do otwarcia \'%1s\'</string>
<string name="sent_file_title">Plik wysłano do %1s</string>
<string name="sent_file_text">%1s</string>
<string name="sent_file_failed_title">Nieudane wysyłanie pliku %1s</string>
<string name="sent_file_failed_title">Nie udało się wyłanie pliku do %1s</string>
<string name="sent_file_failed_text">%1s</string>
<string name="tap_to_answer">Stuknij, aby odpowiedzieć</string>
<string name="reconnect">Połącz ponownie</string>
@@ -132,6 +140,10 @@
<string name="custom_device_list">Dodaj urządzenia po numerze IP</string>
<string name="share_notification_preference">Hałaśliwe powiadomienia</string>
<string name="share_notification_preference_summary">Zadrżyj i odegraj dźwięk przy odebraniu pliku</string>
<string name="share_destination_customize">Własny katalog docelowy</string>
<string name="share_destination_customize_summary_disabled">Pobrane pliki ukażą się w Pobranych</string>
<string name="share_destination_customize_summary_enabled">Pliki zostaną zapisane w poniższym katalogu</string>
<string name="share_destination_folder_preference">Katalog docelowy</string>
<string name="title_activity_notification_filter">Filtr powiadomień</string>
<string name="filter_apps_info">Powiadomienia zostaną zsynchronizowane z wybranymi aplikacjami.</string>
<string name="sftp_internal_storage">"Pamięć wewnętrzna "</string>
@@ -153,6 +165,7 @@
<string name="device_rename_confirm">Zmień nazwę</string>
<string name="refresh">Odśwież</string>
<string name="unreachable_description">To sparowane urządzenie jest nieosiągalne. Upewnij się, że jest podłączone do tej samej sieci.</string>
<string name="on_data_message">Wygląda na to, że korzystasz z internetu mobilnego. KDE Connect działa tylko na lokalnych sieciach.</string>
<string name="no_file_browser">Nie wgrano żadanych przeglądarek plików.</string>
<string name="pref_plugin_telepathy">Wyślij SMS-a</string>
<string name="pref_plugin_telepathy_desc">Wyślij wiadomość tekstową z komputera</string>

View File

@@ -80,7 +80,6 @@
<string name="received_file_text">Toque para abrir o \'%1s\'</string>
<string name="sent_file_title">Enviar arquivo para %1s</string>
<string name="sent_file_text">%1s</string>
<string name="sent_file_failed_title">Falha ao enviar o arquivo %1s</string>
<string name="sent_file_failed_text">%1s</string>
<string name="tap_to_answer">Toque para responder</string>
<string name="reconnect">Reconectar</string>

View File

@@ -10,6 +10,8 @@
<string name="pref_plugin_clipboard_desc">Partilhar o conteúdo da área de transferência</string>
<string name="pref_plugin_mousepad">Introdução remota de dados</string>
<string name="pref_plugin_mousepad_desc">Usar o seu telefone ou \'tablet\' como um rato ou teclado</string>
<string name="pref_plugin_remotekeyboard">Receber as teclas remotamente</string>
<string name="pref_plugin_remotekeyboard_desc">Receber eventos de teclas dos dispositivos remotos</string>
<string name="pref_plugin_mpris">Comandos multimédia</string>
<string name="pref_plugin_mpris_desc">Oferece um comando à distância para o seu leitor multimédia</string>
<string name="pref_plugin_runcommand">Executar um Comando</string>
@@ -19,7 +21,7 @@
<string name="pref_plugin_notifications">Sincronização da notificação</string>
<string name="pref_plugin_notifications_desc">Aceder às suas notificações a partir de outros dispositivos</string>
<string name="pref_plugin_receive_notifications">Receber as notificações</string>
<string name="pref_plugin_receive_notifications_desc">Receber as notificações do outro dispositivo e mostrá-las no Android</string>
<string name="pref_plugin_receive_notifications_desc">Receber as notificações de outros dispositivos e mostrá-las no Android</string>
<string name="pref_plugin_sharereceiver">Partilhar e receber</string>
<string name="pref_plugin_sharereceiver_desc">Partilhar ficheiros e URL\'s entre dispositivos</string>
<string name="plugin_not_available">Esta funcionalidade não está disponível na sua versão do Android</string>
@@ -30,6 +32,10 @@
<string name="no_permissions">Precisa de dar permissões de acesso às notificações</string>
<string name="send_ping">Enviar um pedido de contacto</string>
<string name="open_mpris_controls">Comando multimédia</string>
<string name="remotekeyboard_editing_only_title">Lidar com as teclas remotas apenas na edição</string>
<string name="remotekeyboard_not_connected">Não existe nenhuma ligação activa a teclados remotos - crie uma no \'kdeconnect\'</string>
<string name="remotekeyboard_connected">A ligação ao teclado remoto está activa</string>
<string name="remotekeyboard_multiple_connections">Existe mais que uma ligação a teclados remotos; seleccione o dispositivo a configurar</string>
<string name="open_mousepad">Introdução remota de dados</string>
<string name="mousepad_info">Mova um dedo pelo ecrã para mover o cursor do rato. Dê um toque para carregar no botão esquerdo e use dois/três dedos para os botões direito e do meio. Use uma pressão longa para arrastar e largar.</string>
<string name="mousepad_double_tap_settings_title">Definir a acção do toque com dois dedos</string>
@@ -43,13 +49,13 @@
</string-array>
<string name="mousepad_double_default">direita</string>
<string name="mousepad_triple_default">meio</string>
<string name="mousepad_sensitivity_default">por omissão</string>
<string name="mousepad_sensitivity_default">predefinição</string>
<string-array name="mousepad_sensitivity_entries">
<item>Mais Lenta</item>
<item>Ainda Mais Lenta</item>
<item>Mais Lento</item>
<item>Ainda Mais Lento</item>
<item>Predefinição</item>
<item>Acima da Predefinição</item>
<item>Mais Rápida</item>
<item>Mais Rápido</item>
</string-array>
<string name="category_connected_devices">Dispositivos ligados</string>
<string name="category_not_paired_devices">Dispositivos disponíveis</string>
@@ -68,8 +74,8 @@
<string name="error_canceled_by_user">Cancelado pelo utilizador</string>
<string name="error_canceled_by_other_peer">Cancelado pela outra máquina</string>
<string name="error_invalid_key">Chave inválida recebida</string>
<string name="encryption_info_title">Informação de Encriptação</string>
<string name="encryption_info_msg_no_ssl">O outro dispositivo não usa uma versão recente do KDE Connect; a ser usado o método de encriptação antigo.</string>
<string name="encryption_info_title">Dados de Encriptação</string>
<string name="encryption_info_msg_no_ssl">O outro dispositivo não usa uma versão recente do KDE Connect; será usado o método antigo de encriptação.</string>
<string name="my_device_fingerprint">A impressão digital SHA1 do certificado do seu dispositivo é:</string>
<string name="remote_device_fingerprint">A impressão digital SHA1 do certificado do dispositivo remoto é:</string>
<string name="pair_requested">Emparelhamento pedido</string>
@@ -79,13 +85,15 @@
<string name="incoming_file_title">Ficheiro recebido de %1s</string>
<string name="incoming_file_text">%1s</string>
<string name="outgoing_file_title">A enviar o ficheiro para o %1s</string>
<string name="outgoing_files_title">A enviar os ficheiros para o %1s</string>
<string name="outgoing_file_text">%1s</string>
<string name="outgoing_files_text">Foram enviados %1$d de %2$d ficheiros</string>
<string name="received_file_title">Ficheiro recebido de %1s</string>
<string name="received_file_fail_title">Falhou a recepção do ficheiro de %1s</string>
<string name="received_file_text">Toque para abrir o \'%1s\'</string>
<string name="sent_file_title">O ficheiro foi enviado para %1s</string>
<string name="sent_file_text">%1s</string>
<string name="sent_file_failed_title">Não foi possível enviar o ficheiro %1s</string>
<string name="sent_file_failed_title">Não foi possível enviar o ficheiro para o %1s</string>
<string name="sent_file_failed_text">%1s</string>
<string name="tap_to_answer">Toque para responder</string>
<string name="reconnect">Ligar de Novo</string>
@@ -132,6 +140,10 @@
<string name="custom_device_list">Adicionar dispositivos pelo IP</string>
<string name="share_notification_preference">Notificações com ruído</string>
<string name="share_notification_preference_summary">Vibrar e tocar um som ao receber um ficheiro</string>
<string name="share_destination_customize">Personalizar a pasta de destino</string>
<string name="share_destination_customize_summary_disabled">Os ficheiros recebidos irão aparecer em \'Transferências\'</string>
<string name="share_destination_customize_summary_enabled">Os ficheiros serão guardados na pasta abaixo</string>
<string name="share_destination_folder_preference">Pasta de destino</string>
<string name="title_activity_notification_filter">Filtro de notificações</string>
<string name="filter_apps_info">As notificações serão sincronizadas para as aplicações seleccionadas.</string>
<string name="sftp_internal_storage">Armazenamento interno</string>
@@ -153,6 +165,7 @@
<string name="device_rename_confirm">Mudar o Nome</string>
<string name="refresh">Actualizar</string>
<string name="unreachable_description">Este dispositivo emparelhado não está acessível. Certifique-se que está ligado à mesma rede que você.</string>
<string name="on_data_message">Parece que está com uma ligação de dados móveis. O KDE Connect só se liga em redes locais.</string>
<string name="no_file_browser">Não existem gestores de ficheiros instalados.</string>
<string name="pref_plugin_telepathy">Enviar um SMS</string>
<string name="pref_plugin_telepathy_desc">Enviar mensagens de texto a partir do seu ambiente de trabalho</string>

View File

@@ -5,15 +5,23 @@
<string name="pref_plugin_battery">Состояние батареи</string>
<string name="pref_plugin_battery_desc">Периодическое информирование о состоянии батареи</string>
<string name="pref_plugin_sftp">Просмотр файловой системы</string>
<string name="pref_plugin_sftp_desc">Позволяет удалённо просматривать файловую систему устройства</string>
<string name="pref_plugin_clipboard">Синхронизация буфера обмена</string>
<string name="pref_plugin_clipboard_desc">Использование общего буфера обмена</string>
<string name="pref_plugin_mousepad">Удалённый ввод</string>
<string name="pref_plugin_mousepad_desc">Использование телефона или планшета в качестве сенсорной панели и клавиатуры</string>
<string name="pref_plugin_remotekeyboard">Получение удалённых нажатий клавиш</string>
<string name="pref_plugin_remotekeyboard_desc">Получение нажатий клавиш с удалённых устройств</string>
<string name="pref_plugin_mpris">Управление воспроизведением</string>
<string name="pref_plugin_mpris_desc">Обеспечивает дистанционное управление медиапроигрывателем</string>
<string name="pref_plugin_runcommand">Запуск команд</string>
<string name="pref_plugin_runcommand_desc">Удалённый запуск команд с телефона или планшета</string>
<string name="pref_plugin_ping">Пинг</string>
<string name="pref_plugin_ping_desc">Отправка и получение тестовых сигналов</string>
<string name="pref_plugin_notifications">Синхронизация уведомлений</string>
<string name="pref_plugin_notifications_desc">Доступ к уведомлениям с других устройств</string>
<string name="pref_plugin_receive_notifications">Получение уведомлений</string>
<string name="pref_plugin_receive_notifications_desc">Получение уведомлений с другого устройства и показ их на Android</string>
<string name="pref_plugin_sharereceiver">Отправка и приём данных</string>
<string name="pref_plugin_sharereceiver_desc">Пересылка файлов и адресов URL между устройствами</string>
<string name="plugin_not_available">Эта функциональность недоступна в вашей версии Android</string>
@@ -24,10 +32,16 @@
<string name="no_permissions">Нужно разрешить доступ к уведомлениям</string>
<string name="send_ping">Отправить тестовый сигнал</string>
<string name="open_mpris_controls">Управление воспроизведением</string>
<string name="remotekeyboard_editing_only_title">Обрабатывать удалённые нажатия только при редактировании</string>
<string name="remotekeyboard_not_connected">Нет активного соединения с удалённой клавиатурой, установите его в KDE Connect</string>
<string name="remotekeyboard_connected">Соединение с удалённой клавиатурой активно</string>
<string name="remotekeyboard_multiple_connections">Подключено более одной удалённой клавиатуры, выберите устройство для настройки</string>
<string name="open_mousepad">Удалённый ввод</string>
<string name="mousepad_info">Перемещайте палец по экрану для перемещения курсора мыши. Коснитесь для нажатия, используйте два/три пальца для правой и средней кнопок. Используйте долгое нажатие для перетаскивания.</string>
<string name="mousepad_double_tap_settings_title">Действие при нажатии двумя пальцами</string>
<string name="mousepad_triple_tap_settings_title">Действие при нажатии тремя пальцами</string>
<string name="mousepad_sensitivity_settings_title">Чувствительность сенсорной панели</string>
<string name="mousepad_scroll_direction_title">Инвертировать направление прокрутки</string>
<string-array name="mousepad_tap_entries">
<item>Нажатие правой кнопки</item>
<item>Нажатие средней кнопки</item>
@@ -35,12 +49,13 @@
</string-array>
<string name="mousepad_double_default">Нажатие правой кнопки</string>
<string name="mousepad_triple_default">Нажатие средней кнопки</string>
<string name="mousepad_sensitivity_default">Обычная</string>
<string-array name="mousepad_sensitivity_entries">
<item>Slowest</item>
<item>Above Slowest</item>
<item>Default</item>
<item>Above Default</item>
<item>Fastest</item>
<item>Самая низкая</item>
<item>Низкая</item>
<item>Обычная</item>
<item>Высокая</item>
<item>Самая высокая</item>
</string-array>
<string name="category_connected_devices">Подключённые устройства</string>
<string name="category_not_paired_devices">Доступные устройства</string>
@@ -49,15 +64,20 @@
<string name="device_menu_plugins">Настройка модулей</string>
<string name="device_menu_unpair">Снять сопряжение</string>
<string name="device_not_reachable">Сопряжённое устройство недоступно</string>
<string name="pair_new_device">Подключить новое устройство</string>
<string name="unknown_device">Неизвестное устройство</string>
<string name="error_not_reachable">Устройство недоступно</string>
<string name="error_already_requested">Запрос на сопряжение уже был сделан</string>
<string name="error_already_paired">Устройство уже сопряжено</string>
<string name="error_could_not_send_package">Не удалось отправить пакет.</string>
<string name="error_could_not_send_package">Не удалось отправить пакет</string>
<string name="error_timed_out">Истекло время ожидания</string>
<string name="error_canceled_by_user">Отменено пользователем</string>
<string name="error_canceled_by_other_peer">Отменено другим участником</string>
<string name="error_invalid_key">Получен недопустимый ключ</string>
<string name="encryption_info_title">Информация о шифровании</string>
<string name="encryption_info_msg_no_ssl">На другом устройстве используется старая версия KDE Connect, используется старый метод шифрования.</string>
<string name="my_device_fingerprint">Отпечаток SHA-1 сертификата вашего устройства:</string>
<string name="remote_device_fingerprint">Отпечаток SHA-1 сертификата удалённого устройства:</string>
<string name="pair_requested">Запрошено сопряжение</string>
<string name="pairing_request_from">Запрос на сопряжение от %1s</string>
<string name="received_url_title">Получена ссылка от %1s</string>
@@ -65,13 +85,15 @@
<string name="incoming_file_title">Входящий файл с %1s</string>
<string name="incoming_file_text">%1s</string>
<string name="outgoing_file_title">Отправка файла на %1s</string>
<string name="outgoing_files_title">Отправка файлов на %1s</string>
<string name="outgoing_file_text">%1s</string>
<string name="outgoing_files_text">Отправлено %1$d из %2$d файлов</string>
<string name="received_file_title">Получен файл с %1s</string>
<string name="received_file_fail_title">Не удалось получить файл с %1s</string>
<string name="received_file_text">Нажмите, чтобы открыть «%1s»</string>
<string name="sent_file_title">Файл отправлен на %1s</string>
<string name="sent_file_text">%1s</string>
<string name="sent_file_failed_title">Не удалось отправить файл %1s</string>
<string name="sent_file_failed_title">Не удалось отправить файл на %1s</string>
<string name="sent_file_failed_text">%1s</string>
<string name="tap_to_answer">Нажмите, чтобы ответить</string>
<string name="reconnect">Подключить заново</string>
@@ -103,8 +125,8 @@
<item>2 минуты</item>
</string-array>
<string name="share_to">Отправить на...</string>
<string name="protocol_version_older">Это устройство использует старую версию протокола.</string>
<string name="protocol_version_newer">Это устройство использует более новую версию протокола.</string>
<string name="protocol_version_older">Это устройство использует старую версию протокола</string>
<string name="protocol_version_newer">Это устройство использует более новую версию протокола</string>
<string name="general_settings">Общие параметры</string>
<string name="plugin_settings">Настройка</string>
<string name="plugin_settings_with_name">Настройка %s</string>
@@ -117,7 +139,11 @@
<string name="unpair_device_action">Снять сопряжение с %s</string>
<string name="custom_device_list">Добавить устройства по IP</string>
<string name="share_notification_preference">Звуковые уведомления</string>
<string name="share_notification_preference_summary">Использовать звуковой сигнал и вибрацию при получении файла.</string>
<string name="share_notification_preference_summary">Использовать вибрацию и звуковой сигнал при получении файла</string>
<string name="share_destination_customize">Задать целевой каталог</string>
<string name="share_destination_customize_summary_disabled">Полученные файлы появятся в каталоге Загрузки</string>
<string name="share_destination_customize_summary_enabled">Файлы будут сохранены в указанном ниже каталоге</string>
<string name="share_destination_folder_preference">Целевой каталог</string>
<string name="title_activity_notification_filter">Фильтр уведомлений</string>
<string name="filter_apps_info">Уведомления будут синхронизированы для выбранных приложений.</string>
<string name="sftp_internal_storage">Встроенная память</string>
@@ -139,10 +165,14 @@
<string name="device_rename_confirm">Переименовать</string>
<string name="refresh">Обновить</string>
<string name="unreachable_description">Это сопряжённое устройство недоступно. Проверьте, что оно подключено к той же локальной сети.</string>
<string name="on_data_message">Похоже, вы подключены к мобильной сети. KDE Connect работает только в локальных сетях.</string>
<string name="no_file_browser">Не удалось открыть диалог выбора файла.</string>
<string name="pref_plugin_telepathy">Отправка SMS</string>
<string name="pref_plugin_telepathy_desc">Отправка SMS-сообщений с вашего компьютера</string>
<string name="plugin_not_supported">Этот модуль не поддерживается устройством</string>
<string name="findmyphone_title">Поиск телефона</string>
<string name="findmyphone_title_tablet">Поиск планшета</string>
<string name="findmyphone_description">Подача звукового сигнала на устройстве, чтобы вы могли его найти</string>
<string name="findmyphone_found">Найден</string>
<string name="open">Открыть</string>
<string name="close">Закрыть</string>

View File

@@ -10,6 +10,8 @@
<string name="pref_plugin_clipboard_desc">Zdieľať obsah schránky</string>
<string name="pref_plugin_mousepad">Vzdialený vstup</string>
<string name="pref_plugin_mousepad_desc">Použiť váš telefón alebo tablet ako touchpad a klávesnicu</string>
<string name="pref_plugin_remotekeyboard">Prijímať vzdialené stlačenia klávesov</string>
<string name="pref_plugin_remotekeyboard_desc">Prijímať udalosti stlačení klávesov od vzdialených zariadení</string>
<string name="pref_plugin_mpris">Multimediálne ovládače</string>
<string name="pref_plugin_mpris_desc">Poskytuje vzdialené ovládanie pre váš prehrávač médií</string>
<string name="pref_plugin_runcommand">Spustiť príkaz</string>
@@ -30,6 +32,10 @@
<string name="no_permissions">Musíte povoliť oprávnenia na prístup k pripomienkam</string>
<string name="send_ping">Poslať ping</string>
<string name="open_mpris_controls">Multimediálny ovládač</string>
<string name="remotekeyboard_editing_only_title">Spracúva vzdialené klávesy len pri editácii</string>
<string name="remotekeyboard_not_connected">Nie sú žiadne aktívne pripojenia vzdialenej klávesnice, vytvorte nejaké v Kdeconnect</string>
<string name="remotekeyboard_connected">Vzdialené pripojenie klávesnice je aktívne</string>
<string name="remotekeyboard_multiple_connections">Je viac ako jedno vzdialené pripojenie klávesnice, vyberte zariadenie na nastavenie</string>
<string name="open_mousepad">Vzdialený vstup</string>
<string name="mousepad_info">Posúvajte prst na obrazovke na posun kurzora. Ťuknutie vyvolá klik a použite dva/tri prsty pre pravé a stredné tlačidlo. Použite dlhé stlačenie pre drag and drop.</string>
<string name="mousepad_double_tap_settings_title">Nastaviť akciu dvoch prstov</string>
@@ -79,7 +85,9 @@
<string name="incoming_file_title">Prichádzajúci súbor od %s</string>
<string name="incoming_file_text">%1s</string>
<string name="outgoing_file_title">Posielam súbor pre %1s</string>
<string name="outgoing_files_title">Posielam súbor pre %1s</string>
<string name="outgoing_file_text">%1s</string>
<string name="outgoing_files_text">Poslať %1$d z %2$d súborov</string>
<string name="received_file_title">Prijatý súbor od %1s</string>
<string name="received_file_fail_title">Zlyhalo prijatie súboru od %1s</string>
<string name="received_file_text">Ťuknite na otvorenie \'%1s\'</string>
@@ -132,6 +140,10 @@
<string name="custom_device_list">Pridať zariadenia podľa IP</string>
<string name="share_notification_preference">Hlučné pripomienky</string>
<string name="share_notification_preference_summary">Vibrovať a prehrať zvuk pri prijatí súboru</string>
<string name="share_destination_customize">Prispôsobiť cieľový adresár</string>
<string name="share_destination_customize_summary_disabled">Prijaté súbory sa objavia v Preberaniach</string>
<string name="share_destination_customize_summary_enabled">Súbory sa uložia v adresári dolu</string>
<string name="share_destination_folder_preference">Cieľový adresár</string>
<string name="title_activity_notification_filter">Filter upozornení</string>
<string name="filter_apps_info">Upozornenia budú synchronizované pre vybrané aplikácie.</string>
<string name="sftp_internal_storage">Interné úložisko</string>
@@ -153,6 +165,7 @@
<string name="device_rename_confirm">Premenovať</string>
<string name="refresh">Obnoviť</string>
<string name="unreachable_description">Toto spárované zariadenie nie je dosiahnuteľné. Prosím, uistite sa, že je pripojené do rovnakej siete.</string>
<string name="on_data_message">Zdá sa, že ste na mobilom dátovom pripojení. KDE Connect funguje iba na lokálnej sieti.</string>
<string name="no_file_browser">Nie sú nainštalované žiadne prehliadače.</string>
<string name="pref_plugin_telepathy">Poslať SMS</string>
<string name="pref_plugin_telepathy_desc">Posielať textové správy z vášho počítača</string>

View File

@@ -10,6 +10,8 @@
<string name="pref_plugin_clipboard_desc">Dela klippbordets innehåll</string>
<string name="pref_plugin_mousepad">Fjärrinmatning</string>
<string name="pref_plugin_mousepad_desc">Använd telefonen eller surfplattan som mus och tangentbord</string>
<string name="pref_plugin_remotekeyboard">Ta emot fjärrtangentnedtryckningar</string>
<string name="pref_plugin_remotekeyboard_desc">Ta emot tangentnedtryckningar från fjärrenheter</string>
<string name="pref_plugin_mpris">Multimediakontroller</string>
<string name="pref_plugin_mpris_desc">Tillhandahåller en fjärrkontroll för mediaspelaren</string>
<string name="pref_plugin_runcommand">Kör kommando</string>
@@ -30,6 +32,10 @@
<string name="no_permissions">Du måste ge rättighet att komma åt underrättelser</string>
<string name="send_ping">Skicka ping</string>
<string name="open_mpris_controls">Kontroll av multimedia</string>
<string name="remotekeyboard_editing_only_title">Hantera bara fjärrtangenter vid redigering</string>
<string name="remotekeyboard_not_connected">Det finns ingen aktiv fjärrtangentbordsanslutning, upprätta en i KDE-anslut</string>
<string name="remotekeyboard_connected">Fjärrtangentbordsanslutning är aktiv</string>
<string name="remotekeyboard_multiple_connections">Det finns mer än en fjärrtangentbordsanslutning, välj enhet att anpassa</string>
<string name="open_mousepad">Fjärrinmatning</string>
<string name="mousepad_info">Flytta fingret på skärmen för att röra muspekaren. Rör för att klicka, och använd två eller tre fingrar för höger- och mittenknapparna. Använd en längre beröring för drag och släpp.</string>
<string name="mousepad_double_tap_settings_title">Ställ in åtgärd vid två fingerberöringar</string>
@@ -79,13 +85,15 @@
<string name="incoming_file_title">Inkommande fil från %1s</string>
<string name="incoming_file_text">%1s</string>
<string name="outgoing_file_title">Skickar fil till %1s</string>
<string name="outgoing_files_title">Skickar filer till %1s</string>
<string name="outgoing_file_text">%1s</string>
<string name="outgoing_files_text">Skickade %1$d av %2$d filer</string>
<string name="received_file_title">Tog emot fil från %1s</string>
<string name="received_file_fail_title">Misslyckades ta emot fil från %1s</string>
<string name="received_file_text">Rör för att öppna \'%1s\'</string>
<string name="sent_file_title">Skickade fil till %1s</string>
<string name="sent_file_text">%1s</string>
<string name="sent_file_failed_title">Misslyckades skicka fil %1s</string>
<string name="sent_file_failed_title">Misslyckades skicka fil till %1s</string>
<string name="sent_file_failed_text">%1s</string>
<string name="tap_to_answer">Rör för att svara</string>
<string name="reconnect">Anslut igen</string>
@@ -132,6 +140,10 @@
<string name="custom_device_list">Lägg till apparater enligt IP-adress</string>
<string name="share_notification_preference">Ljudliga underrättelser</string>
<string name="share_notification_preference_summary">Vibrera och spela ett ljud när en fil tas emot</string>
<string name="share_destination_customize">Anpassa målkatalog</string>
<string name="share_destination_customize_summary_disabled">Mottagna filer hamnar i Nerladdningar</string>
<string name="share_destination_customize_summary_enabled">Filer lagras i katalogen nedan</string>
<string name="share_destination_folder_preference">Målkatalog</string>
<string name="title_activity_notification_filter">Underrättelsefilter</string>
<string name="filter_apps_info">Underrättelser synkroniseras för markerade applikationer.</string>
<string name="sftp_internal_storage">Intern lagring</string>
@@ -153,6 +165,7 @@
<string name="device_rename_confirm">Byt namn</string>
<string name="refresh">Uppdatera</string>
<string name="unreachable_description">Den här ihopparade apparaten kan inte nås. Försäkra dig om att den är ansluten till samma nätverk.</string>
<string name="on_data_message">Det verkar som om du använder en mobil dataanslutning. KDE-anslut fungerar bara på lokala nätverk.</string>
<string name="no_file_browser">Det finns inga filbläddrare installerade.</string>
<string name="pref_plugin_telepathy">Skicka SMS</string>
<string name="pref_plugin_telepathy_desc">Skicka textmeddelanden från skrivbordet</string>

View File

@@ -10,6 +10,8 @@
<string name="pref_plugin_clipboard_desc">Спільне використання буфера обміну даними</string>
<string name="pref_plugin_mousepad">Дистанційне введення</string>
<string name="pref_plugin_mousepad_desc">Скористайтеся телефоном або планшетом як замінником сенсорної панелі і клавіатури</string>
<string name="pref_plugin_remotekeyboard">Отримувати віддалені натискання клавіш</string>
<string name="pref_plugin_remotekeyboard_desc">Отримувати події натискання клавіш з віддаленого пристрою</string>
<string name="pref_plugin_mpris">Керування відтворенням</string>
<string name="pref_plugin_mpris_desc">Надає можливість віддаленого керування вашим мультимедійним програвачем</string>
<string name="pref_plugin_runcommand">Виконати команду</string>
@@ -30,6 +32,10 @@
<string name="no_permissions">Вам слід надати доступ до сповіщень</string>
<string name="send_ping">Надіслати сигнал підтримання зв’язку</string>
<string name="open_mpris_controls">Керування відтворенням</string>
<string name="remotekeyboard_editing_only_title">Обробляти віддалені клавіші лише під час редагування</string>
<string name="remotekeyboard_not_connected">Немає активних з’єднань із віддаленою клавіатурою. Встановіть таке з’єднання у kdeconnect.</string>
<string name="remotekeyboard_connected">З’єднання з віддаленою клавіатурою є активним</string>
<string name="remotekeyboard_multiple_connections">Існує декілька з’єднань із віддаленою клавіатурою. Виберіть пристрій для налаштовування.</string>
<string name="open_mousepad">Дистанційне введення</string>
<string name="mousepad_info">Проведіть по екрану пальцем, щоб пересунути вказівник миші. Дотик одним пальцем означатиме клацання, дотиком двома або трьома пальцями можна імітувати праву і середню кнопки. Для перетягування зі скиданням скористайтеся тривалим натисканням.</string>
<string name="mousepad_double_tap_settings_title">Встановлення дії для торкання двома пальцями</string>
@@ -79,13 +85,15 @@
<string name="incoming_file_title">Вхідний файл з %1s</string>
<string name="incoming_file_text">%1s</string>
<string name="outgoing_file_title">Надсилаємо файл до %1s</string>
<string name="outgoing_files_title">Надсилаємо файли на %1s</string>
<string name="outgoing_file_text">%1s</string>
<string name="outgoing_files_text">Надіслано %1$d з %2$d файлів</string>
<string name="received_file_title">Отримано файл з %1s</string>
<string name="received_file_fail_title">Не вдалося отримати файл з %1s</string>
<string name="received_file_text">Натисніть, щоб відкрити «%1s»</string>
<string name="sent_file_title">Файл надіслано до %1s</string>
<string name="sent_file_text">%1s</string>
<string name="sent_file_failed_title">Не вдалося надіслати файл %1s</string>
<string name="sent_file_failed_title">Не вдалося надіслати файл на %1s</string>
<string name="sent_file_failed_text">%1s</string>
<string name="tap_to_answer">Натисніть, щоб відповісти</string>
<string name="reconnect">З\'єднати знову</string>
@@ -132,6 +140,10 @@
<string name="custom_device_list">Додати пристрої за IP</string>
<string name="share_notification_preference">Звукові сповіщення</string>
<string name="share_notification_preference_summary">Вібрація і відтворення звуку у відповідь на отримання файла</string>
<string name="share_destination_customize">Налаштування каталогу призначення</string>
<string name="share_destination_customize_summary_disabled">Отримані файли зберігатимуться до каталогу «Завантаження»</string>
<string name="share_destination_customize_summary_enabled">Файли зберігатимуться у вказаному нижче каталозі</string>
<string name="share_destination_folder_preference">Каталог призначення</string>
<string name="title_activity_notification_filter">Фільтр сповіщень</string>
<string name="filter_apps_info">Сповіщення буде синхронізовано для позначених програм.</string>
<string name="sftp_internal_storage">Вбудоване сховище даних</string>
@@ -153,6 +165,7 @@
<string name="device_rename_confirm">Перейменувати</string>
<string name="refresh">Оновити</string>
<string name="unreachable_description">Цей пов’язаний пристрій недоступний. Переконайтеся, що його з’єднано з вашою мережею.</string>
<string name="on_data_message">Здається, мережа працює у режимі мобільного з’єднання. KDE Connect може працювати лише у локальних мережах.</string>
<string name="no_file_browser">Програм для навігації файловою системою не встановлено.</string>
<string name="pref_plugin_telepathy">Надіслати SMS</string>
<string name="pref_plugin_telepathy_desc">Надсилати текстові повідомлення з вашої робочої станції</string>

View File

@@ -5,15 +5,23 @@
<string name="pref_plugin_battery">电池报告</string>
<string name="pref_plugin_battery_desc">定期报告电池状态</string>
<string name="pref_plugin_sftp">开放文件系统</string>
<string name="pref_plugin_sftp_desc">允许远程浏览设备的文件系统</string>
<string name="pref_plugin_clipboard">剪贴板同步</string>
<string name="pref_plugin_clipboard_desc">共享剪贴板内容</string>
<string name="pref_plugin_mousepad">远程输入</string>
<string name="pref_plugin_mousepad_desc">将您的手机用或平板电脑用作触摸板和键盘</string>
<string name="pref_plugin_remotekeyboard">接收远程按键</string>
<string name="pref_plugin_remotekeyboard_desc">从远程设备接收按键事件</string>
<string name="pref_plugin_mpris">多媒体控制</string>
<string name="pref_plugin_mpris_desc">媒体播放器的遥控器</string>
<string name="pref_plugin_runcommand">执行命令</string>
<string name="pref_plugin_runcommand_desc">触发您的手机或平板电脑的远程命令</string>
<string name="pref_plugin_ping">Ping</string>
<string name="pref_plugin_ping_desc">发送和接受ping</string>
<string name="pref_plugin_notifications">通知同步</string>
<string name="pref_plugin_notifications_desc">从其他设备访问你的通知</string>
<string name="pref_plugin_receive_notifications">接收通知</string>
<string name="pref_plugin_receive_notifications_desc">从其他设备接收通知并显示在 Android 上</string>
<string name="pref_plugin_sharereceiver">分享和接收</string>
<string name="pref_plugin_sharereceiver_desc">在设备间共享文件和 URL</string>
<string name="plugin_not_available">该特性不适用于您的Android版本</string>
@@ -24,10 +32,16 @@
<string name="no_permissions">你需要授予权限以便访问通知</string>
<string name="send_ping">发送ping</string>
<string name="open_mpris_controls">多媒体控制</string>
<string name="remotekeyboard_editing_only_title">只有在编辑时才接受远程按键</string>
<string name="remotekeyboard_not_connected">没有活动的远程键盘链接,请在 KDE Connect 中连接</string>
<string name="remotekeyboard_connected">远程键盘连接已启用</string>
<string name="remotekeyboard_multiple_connections">发现多个远程键盘连接,请选择设备进行配置</string>
<string name="open_mousepad">远程输入</string>
<string name="mousepad_info">在屏幕上移动手指来移动光标。轻击代表左键,双指或三指点击代表右键或中键。用长按来拖放。</string>
<string name="mousepad_double_tap_settings_title">设置双指点击动作</string>
<string name="mousepad_triple_tap_settings_title">设置三指点击动作</string>
<string name="mousepad_sensitivity_settings_title">设置触摸板灵敏度</string>
<string name="mousepad_scroll_direction_title">滚动方向反向</string>
<string-array name="mousepad_tap_entries">
<item>右键点击</item>
<item>中键点击</item>
@@ -35,12 +49,13 @@
</string-array>
<string name="mousepad_double_default"></string>
<string name="mousepad_triple_default"></string>
<string name="mousepad_sensitivity_default">默认</string>
<string-array name="mousepad_sensitivity_entries">
<item>Slowest</item>
<item>Above Slowest</item>
<item>Default</item>
<item>Above Default</item>
<item>Fastest</item>
<item>最慢</item>
<item>高于最慢</item>
<item>默认</item>
<item>高于默认</item>
<item>最快</item>
</string-array>
<string name="category_connected_devices">已连接设备</string>
<string name="category_not_paired_devices">可用设备</string>
@@ -59,6 +74,10 @@
<string name="error_canceled_by_user">已被用户取消</string>
<string name="error_canceled_by_other_peer">已被另一方取消</string>
<string name="error_invalid_key">收到无效密钥</string>
<string name="encryption_info_title">加密信息</string>
<string name="encryption_info_msg_no_ssl">另一设备没有使用最新的 KDE Connect使用旧版加密方法。</string>
<string name="my_device_fingerprint">您的设备证书的 SHA1 指纹是:</string>
<string name="remote_device_fingerprint">远程设备证书的 SHA1 指纹是:</string>
<string name="pair_requested">已请求配对</string>
<string name="pairing_request_from">来自%1s的配对请求</string>
<string name="received_url_title">已从%1s接收链接</string>
@@ -66,13 +85,15 @@
<string name="incoming_file_title">来自%1s的文件</string>
<string name="incoming_file_text">%1s</string>
<string name="outgoing_file_title">正在向%1s发送文件</string>
<string name="outgoing_files_title">正在向 %1s 发送文件</string>
<string name="outgoing_file_text">%1s</string>
<string name="outgoing_files_text">已发送 %2$d 个文件中的 %1$d 个</string>
<string name="received_file_title">已从%1s接收文件</string>
<string name="received_file_fail_title">未能从%1s接收文件</string>
<string name="received_file_text">点击以打开“%1s”</string>
<string name="sent_file_title">发送文件到%1s</string>
<string name="sent_file_text">%1s</string>
<string name="sent_file_failed_title">未能发送文件%1s</string>
<string name="sent_file_failed_title">向 %1s 发送文件失败</string>
<string name="sent_file_failed_text">%1s</string>
<string name="tap_to_answer">点击以应答</string>
<string name="reconnect">重新连接</string>
@@ -119,6 +140,10 @@
<string name="custom_device_list">通过IP增加设备</string>
<string name="share_notification_preference">出声通知</string>
<string name="share_notification_preference_summary">当收到文件时震动并播放声音</string>
<string name="share_destination_customize">配置目标目录</string>
<string name="share_destination_customize_summary_disabled">接收的文件会出现在“Downloads”中</string>
<string name="share_destination_customize_summary_enabled">文件将会被存储在以下目录中</string>
<string name="share_destination_folder_preference">目标目录</string>
<string name="title_activity_notification_filter">通知过滤器</string>
<string name="filter_apps_info">所选软件的通知将会被同步。</string>
<string name="sftp_internal_storage">内部存储</string>
@@ -144,5 +169,7 @@
<string name="pref_plugin_telepathy">发送短消息</string>
<string name="pref_plugin_telepathy_desc">从桌面发送短消息</string>
<string name="plugin_not_supported">设备不支持此插件</string>
<string name="findmyphone_title">找到我的手机</string>
<string name="findmyphone_description">让设备响铃从而找到它</string>
<string name="findmyphone_found">找到</string>
</resources>

View File

@@ -1,22 +1,165 @@
<?xml version='1.0' encoding='utf-8'?>
<resources>
<string name="pref_plugin_telephony">電話通知器</string>
<string name="pref_plugin_telephony_desc">發送短訊與電話的通知</string>
<string name="pref_plugin_battery">電池報告</string>
<string name="pref_plugin_battery_desc">定期回報電池狀態</string>
<string name="pref_plugin_sftp">顯示檔案系統</string>
<string name="pref_plugin_sftp_desc">同意讓遠端可以瀏覽檔案系統</string>
<string name="pref_plugin_clipboard">同步剪貼板</string>
<string name="pref_plugin_clipboard_desc">分享剪貼板的內容</string>
<string name="pref_plugin_mousepad">遠端輸入</string>
<string name="pref_plugin_mousepad_desc">使用您的智慧型手機或者平板來模擬觸碰板與鍵盤</string>
<string name="pref_plugin_mpris">多媒體控制</string>
<string name="pref_plugin_mpris_desc">成為您多媒體播放器的遙控器</string>
<string name="pref_plugin_runcommand">執行指令</string>
<string name="pref_plugin_runcommand_desc">從您的智慧型手機或者平板當中觸發遠端設備上的命令</string>
<string name="pref_plugin_ping">Ping回應封包</string>
<string name="pref_plugin_ping_desc">傳送與接收Ping回應封包</string>
<string name="pref_plugin_notifications">同步通知</string>
<string name="pref_plugin_notifications_desc">存取其他設備上的通知</string>
<string name="pref_plugin_receive_notifications">接收通知</string>
<string name="pref_plugin_receive_notifications_desc">在Android上顯示從其他裝置收到的通知</string>
<string name="pref_plugin_sharereceiver">分享與接收</string>
<string name="pref_plugin_sharereceiver_desc">在兩個設備當中互相分享URL網址與檔案</string>
<string name="plugin_not_available">這個功能無法在您的Android版本上執行。</string>
<string name="device_list_empty">沒有裝置</string>
<string name="ok">OK</string>
<string name="cancel">取消</string>
<string name="open_settings">開啟設定</string>
<string name="no_permissions">您需要授予存取通知的權限</string>
<string name="send_ping">傳送Ping回應封包</string>
<string name="open_mpris_controls">多媒體控制</string>
<string name="open_mousepad">遠端輸入</string>
<string name="mousepad_info">在您的智慧型手機的螢幕上移動手指頭,用來控制電腦螢幕的鼠標。點擊表示滑鼠的左鍵,使用兩隻/三隻手指頭點擊來表示滑鼠的右鍵/中鍵。長按則表示要拖拉。</string>
<string name="mousepad_double_tap_settings_title">設定兩隻手指頭點擊的動作</string>
<string name="mousepad_triple_tap_settings_title">設定三隻手指頭點擊的動作</string>
<string name="mousepad_sensitivity_settings_title">設定觸碰板的靈敏度</string>
<string name="mousepad_scroll_direction_title">滾動方向相反</string>
<string-array name="mousepad_tap_entries">
<item>Right click</item>
<item>Middle click</item>
<item>Nothing</item>
<item>右鍵點擊</item>
<item>中鍵點擊</item>
<item></item>
</string-array>
<string name="mousepad_double_default"></string>
<string name="mousepad_triple_default"></string>
<string name="mousepad_sensitivity_default">預設</string>
<string-array name="mousepad_sensitivity_entries">
<item>Slowest</item>
<item>Above Slowest</item>
<item>Default</item>
<item>Above Default</item>
<item>Fastest</item>
<item></item>
<item>最慢</item>
<item>預設</item>
<item>高於預設值</item>
<item>最快</item>
</string-array>
<string name="category_connected_devices">已連接的設備</string>
<string name="category_not_paired_devices">可連接的設備</string>
<string name="category_remembered_devices">已記住的設備</string>
<string name="plugins_failed_to_load">擴展插件讀取錯誤(點擊查看更多資訊)</string>
<string name="device_menu_plugins">擴展插件設定</string>
<string name="device_menu_unpair">取消配對</string>
<string name="device_not_reachable">配對的設備無法連接</string>
<string name="pair_new_device">配對新設備</string>
<string name="unknown_device">不明的設備</string>
<string name="error_not_reachable">設備無法連接</string>
<string name="error_already_requested">已請求配對</string>
<string name="error_already_paired">裝置已經配對</string>
<string name="error_could_not_send_package">無法傳送封包</string>
<string name="error_timed_out">逾時</string>
<string name="error_canceled_by_user">使用者中斷</string>
<string name="error_canceled_by_other_peer">被其他同等功能應用中斷</string>
<string name="error_invalid_key">接收的密鑰無效</string>
<string name="encryption_info_title">加密資訊</string>
<string name="encryption_info_msg_no_ssl">其他的設備沒有使用新版本的KDE連線使用傳統的加密模式。</string>
<string name="my_device_fingerprint">您設備上的SHA1指紋辨識認證是</string>
<string name="remote_device_fingerprint">您遠端設備上的SHA1指紋辨識認證是</string>
<string name="pair_requested">已請求配對</string>
<string name="pairing_request_from">從 %1s 來的配對請求</string>
<string name="received_url_title">已從 %1s 連線接收</string>
<string name="received_url_text">點擊開啟 \'%1s\'</string>
<string name="incoming_file_title">從 %1s 傳來的檔案</string>
<string name="incoming_file_text">%1s</string>
<string name="outgoing_file_title">正在將檔案發送到 %1s</string>
<string name="outgoing_file_text">%1s</string>
<string name="received_file_title">已從 %1s 接收檔案</string>
<string name="received_file_fail_title">從 %1s 接收檔案失敗</string>
<string name="received_file_text">點擊開啟 \'%1s\'</string>
<string name="sent_file_title">將檔案傳送到 %1s</string>
<string name="sent_file_text">%1s</string>
<string name="sent_file_failed_text">%1s</string>
<string name="tap_to_answer">點擊即可應答</string>
<string name="reconnect">重新連線</string>
<string name="right_click">傳送右鍵點擊</string>
<string name="middle_click">傳送中鍵點擊</string>
<string name="show_keyboard">顯示鍵盤</string>
<string name="device_not_paired">裝置未配對</string>
<string name="request_pairing">請求配對</string>
<string name="pairing_accept">同意</string>
<string name="pairing_reject">回絕</string>
<string name="device">裝置</string>
<string name="pair_device">配對裝置</string>
<string name="remote_control">遠端控制</string>
<string name="settings">KDE連線設定</string>
<string name="mpris_play">播放</string>
<string name="mpris_previous">往前</string>
<string name="mpris_rew">往後</string>
<string name="mpris_ff">快轉</string>
<string name="mpris_next">下一首</string>
<string name="mpris_volume">音量</string>
<string name="mpris_settings">多媒體設定</string>
<string name="mpris_time_settings_title">往前/往後按鍵</string>
<string name="mpris_time_settings_summary">調整按下時往前/往後的時間。</string>
<string-array name="mpris_time_entries">
<item>10 seconds</item>
<item>20 seconds</item>
<item>30 seconds</item>
<item>1 minute</item>
<item>2 minutes</item>
<item>10秒鐘</item>
<item>20秒鐘</item>
<item>30秒鐘</item>
<item>1分鐘</item>
<item>2分鐘</item>
</string-array>
<string name="share_to">分享給</string>
<string name="protocol_version_older">這個裝置使用舊版本的通訊協定</string>
<string name="protocol_version_newer">此設備使用較新的通訊協定</string>
<string name="general_settings">通用設定</string>
<string name="plugin_settings">設定</string>
<string name="plugin_settings_with_name">%s 設定</string>
<string name="device_name">設備名稱</string>
<string name="device_name_preference_summary">%s</string>
<string name="invalid_device_name">無效的設備名稱</string>
<string name="shareplugin_text_saved">已接收文字,並且儲存到剪貼簿</string>
<string name="custom_devices_settings">自定義設備列表</string>
<string name="pair_device_action">配對新設備</string>
<string name="unpair_device_action">未配對 %s</string>
<string name="custom_device_list">以IP來新增設備</string>
<string name="share_notification_preference">通知方式</string>
<string name="share_notification_preference_summary">當接收檔案時發出振動以及播放聲音</string>
<string name="title_activity_notification_filter">通知過濾器</string>
<string name="filter_apps_info">將會以您選擇的App應用程式啟用同步通知</string>
<string name="sftp_internal_storage">內部儲存空間</string>
<string name="sftp_all_files">全部檔案</string>
<string name="sftp_sdcard_num">SD卡 %d</string>
<string name="sftp_sdcard">SD卡</string>
<string name="sftp_readonly">(唯讀)</string>
<string name="sftp_camera">相機圖片</string>
<string name="add_host">增加 host/IP</string>
<string name="add_host_hint">Hostname或者IP</string>
<string name="no_players_connected">沒有發現播放器</string>
<string name="custom_dev_list_help">能夠在您的裝置沒有自動偵測到裝置時使用這個選項。輸入IP位址或者是Hostname在下面並且按下按鈕來增加進入列表當中。觸碰以從列表中刪除現有項目。</string>
<string name="mpris_player_on_device">%1$s on %2$s</string>
<string name="send_files">傳送檔案</string>
<string name="pairing_title">KDE連線裝置</string>
<string name="pairing_description">在您相同網域當中有其他有執行KDE連線的裝置會出現在這裡。</string>
<string name="device_paired">裝置已配對</string>
<string name="device_rename_title">更改裝置名稱</string>
<string name="device_rename_confirm">更改名稱</string>
<string name="refresh">刷新</string>
<string name="unreachable_description">此配對的裝置無法連接。 請確保它連接到與您相同的網域。</string>
<string name="no_file_browser">沒有安裝此檔案的瀏覽程式</string>
<string name="pref_plugin_telepathy">傳送簡訊</string>
<string name="pref_plugin_telepathy_desc">傳送文字簡訊到您的電腦桌面</string>
<string name="plugin_not_supported">這個擴充插件並不支援您的手機</string>
<string name="findmyphone_title">找尋我的手機</string>
<string name="findmyphone_title_tablet">找尋我的平板</string>
<string name="findmyphone_description">讓這個裝置發出聲響讓您能找到它</string>
<string name="findmyphone_found">找到</string>
<string name="open">開啟</string>
<string name="close">關閉</string>
</resources>

View File

@@ -2,4 +2,5 @@
<!-- Default screen margins, per the Android Design guidelines. -->
<dimen name="activity_horizontal_margin">16dp</dimen>
<dimen name="activity_vertical_margin">16dp</dimen>
<dimen name="key_height">48dip</dimen>
</resources>

View File

@@ -11,6 +11,8 @@
<string name="pref_plugin_clipboard_desc">Share the clipboard content</string>
<string name="pref_plugin_mousepad">Remote input</string>
<string name="pref_plugin_mousepad_desc">Use your phone or tablet as a touchpad and keyboard</string>
<string name="pref_plugin_remotekeyboard">Receive remote keypresses</string>
<string name="pref_plugin_remotekeyboard_desc">Receive keypress events from remote devices</string>
<string name="pref_plugin_mpris">Multimedia controls</string>
<string name="pref_plugin_mpris_desc">Provides a remote control for your media player</string>
<string name="pref_plugin_runcommand">Run Command</string>
@@ -31,6 +33,11 @@
<string name="no_permissions">You need to grant permission to access notifications</string>
<string name="send_ping">Send ping</string>
<string name="open_mpris_controls">Multimedia control</string>
<string name="remotekeyboard_editing_only" translatable="false">remotekeyboard_editing_only</string>
<string name="remotekeyboard_editing_only_title" translatable="true">Handle remote keys only when editing</string>
<string name="remotekeyboard_not_connected" translatable="true">There is no active remote keyboard connection, establish one in kdeconnect</string>
<string name="remotekeyboard_connected" translatable="true">Remote keyboard connection is active</string>
<string name="remotekeyboard_multiple_connections" translatable="true">There is more than one remote keyboard connection, select the device to configure</string>
<string name="open_mousepad">Remote input</string>
<string name="mousepad_info">Move a finger on the screen to move the mouse cursor. Tap for a click, and use two/three fingers for right and middle buttons. Use a long press to drag\'n drop.</string>
<string name="mousepad_double_tap_settings_title">Set two finger tap action</string>
@@ -96,13 +103,15 @@
<string name="incoming_file_title">Incoming file from %1s</string>
<string name="incoming_file_text">%1s</string>
<string name="outgoing_file_title">Sending file to %1s</string>
<string name="outgoing_files_title">Sending files to %1s</string>
<string name="outgoing_file_text">%1s</string>
<string name="outgoing_files_text">Sent %1$d out of %2$d files</string>
<string name="received_file_title">Received file from %1s</string>
<string name="received_file_fail_title">Failed receiving file from %1s</string>
<string name="received_file_text">Tap to open \'%1s\'</string>
<string name="sent_file_title">Sent file to %1s</string>
<string name="sent_file_text">%1s</string>
<string name="sent_file_failed_title">Failed to send file %1s</string>
<string name="sent_file_failed_title">Failed to send file to %1s</string>
<string name="sent_file_failed_text">%1s</string>
<string name="tap_to_answer">Tap to answer</string>
<string name="reconnect">Reconnect</string>
@@ -158,6 +167,10 @@
<string name="custom_device_list">Add devices by IP</string>
<string name="share_notification_preference">Noisy notifications</string>
<string name="share_notification_preference_summary">Vibrate and play a sound when receiving a file</string>
<string name="share_destination_customize">Customize destination directory</string>
<string name="share_destination_customize_summary_disabled">Received files will appear in Downloads</string>
<string name="share_destination_customize_summary_enabled">Files will be stored in the directory below</string>
<string name="share_destination_folder_preference">Destination directory</string>
<string name="title_activity_notification_filter">Notification filter</string>
<string name="filter_apps_info">Notifications will be synchronized for the selected apps.</string>
<string name="sftp_internal_storage">Internal storage</string>
@@ -180,6 +193,7 @@
<string name="device_rename_confirm">Rename</string>
<string name="refresh">Refresh</string>
<string name="unreachable_description">This paired device is not reachable. Make sure it is connected to your same network.</string>
<string name="on_data_message">It looks like you are on a mobile data connection. KDE Connect only works on local networks.</string>
<string name="no_file_browser">There are no file browsers installed.</string>
<string name="pref_plugin_telepathy">Send SMS</string>
<string name="pref_plugin_telepathy_desc">Send text messages from your desktop</string>
@@ -191,4 +205,5 @@
<string name="open">Open</string>
<string name="close">Close</string>
</resources>

View File

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<Keyboard
xmlns:android="http://schemas.android.com/apk/res/android"
android:keyHeight="@dimen/key_height"
android:horizontalGap="0px"
android:verticalGap="0px" >
<Row android:rowEdgeFlags="bottom">
<Key android:keyIcon="@drawable/ic_keyboard_hide_white_36dp" android:codes="0" android:keyWidth="20%" />
<Key android:keyIcon="@drawable/ic_action_settings" android:codes="1" android:keyWidth="40%"/>
<Key android:keyIcon="@drawable/ic_action_keyboard" android:codes="2" android:keyWidth="40%"/>
<Key android:keyIcon="@drawable/ic_phonelink_white_36dp" android:codes="3" android:keyWidth="20%" />-->
</Row>
</Keyboard>

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<input-method xmlns:android="http://schemas.android.com/apk/res/android"
android:supportsSwitchingToNextInputMethod="true">
</input-method>

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<CheckBoxPreference
android:id="@+id/remotekeyboard_editing_only"
android:key="@string/remotekeyboard_editing_only"
android:title="@string/remotekeyboard_editing_only_title"
android:defaultValue="true" />
</PreferenceScreen>

View File

@@ -3,6 +3,19 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
<CheckBoxPreference
android:id="@+id/share_destination_customize"
android:key="share_destination_custom"
android:title="@string/share_destination_customize"
android:summaryOff="@string/share_destination_customize_summary_disabled"
android:summaryOn="@string/share_destination_customize_summary_enabled"
android:defaultValue="false" />
<Preference
android:id="@+id/share_destination_folder_preference"
android:key="share_destination_folder_preference"
android:title="@string/share_destination_folder_preference" />
<CheckBoxPreference
android:id="@+id/share_notification_preference"
android:key="share_notification_preference"

View File

@@ -89,7 +89,7 @@ public abstract class BaseLink {
}
//TO OVERRIDE, should be sync
public abstract void sendPackage(NetworkPackage np,Device.SendPackageStatusCallback callback);
public abstract boolean sendPackage(NetworkPackage np,Device.SendPackageStatusCallback callback);
@Deprecated
public abstract void sendPackageEncrypted(NetworkPackage np,Device.SendPackageStatusCallback callback, PublicKey key);
public abstract boolean sendPackageEncrypted(NetworkPackage np,Device.SendPackageStatusCallback callback, PublicKey key);
}

View File

@@ -23,8 +23,6 @@ package org.kde.kdeconnect.Backends;
import org.kde.kdeconnect.Device;
import org.kde.kdeconnect.NetworkPackage;
import java.util.Timer;
/**
* This class separates the pairing interface for each type of link.
* Since different links can pair via different methods, like for LanLink certificate and public key should be shared,

View File

@@ -61,7 +61,7 @@ public class LanLink extends BaseLink {
// because it's probably trying to find me and
// potentially ask for pairing.
private Socket socket = null;
private volatile Socket socket = null;
private LinkDisconnectedCallback callback;
@@ -142,11 +142,11 @@ public class LanLink extends BaseLink {
}
//Blocking, do not call from main thread
private void sendPackageInternal(NetworkPackage np, final Device.SendPackageStatusCallback callback, PublicKey key) {
private boolean sendPackageInternal(NetworkPackage np, final Device.SendPackageStatusCallback callback, PublicKey key) {
if (socket == null) {
Log.e("KDE/sendPackage", "Not yet connected");
callback.sendFailure(new NotYetConnectedException());
return;
callback.onFailure(new NotYetConnectedException());
return false;
}
try {
@@ -171,14 +171,12 @@ public class LanLink extends BaseLink {
//Send body of the network package
try {
OutputStream writter = socket.getOutputStream();
writter.write(np.serialize().getBytes(StringsHelper.UTF8));
writter.flush();
OutputStream writer = socket.getOutputStream();
writer.write(np.serialize().getBytes(StringsHelper.UTF8));
writer.flush();
} catch (Exception e) {
callback.sendFailure(e);
e.printStackTrace();
disconnect();
return;
disconnect(); //main socket is broken, disconnect
throw e;
}
//Send payload
@@ -203,23 +201,24 @@ public class LanLink extends BaseLink {
Log.i("KDE/LanLink", "Beginning to send payload");
byte[] buffer = new byte[4096];
int bytesRead;
long size = np.getPayloadSize();
long progress = 0;
long timeSinceLastUpdate = -1;
while ((bytesRead = inputStream.read(buffer)) != -1) {
//Log.e("ok",""+bytesRead);
progress += bytesRead;
outputStream.write(buffer, 0, bytesRead);
if (np.getPayloadSize() > 0) {
callback.sendProgress((int)(progress / np.getPayloadSize()));
if (size > 0) {
if (timeSinceLastUpdate + 500 < System.currentTimeMillis()) { //Report progress every half a second
long percent = ((100 * progress) / size);
callback.onProgressChanged((int) percent);
timeSinceLastUpdate = System.currentTimeMillis();
}
}
}
outputStream.flush();
outputStream.close();
Log.i("KDE/LanLink", "Finished sending payload ("+progress+" bytes written)");
} catch (Exception e) {
e.printStackTrace();
Log.e("KDE/sendPackage", "Exception: "+e);
callback.sendFailure(e);
return;
} finally {
try { server.close(); } catch (Exception e) { }
try { payloadSocket.close(); } catch (Exception e) { }
@@ -228,12 +227,13 @@ public class LanLink extends BaseLink {
}
}
callback.sendSuccess();
callback.onSuccess();
return true;
} catch (Exception e) {
if (callback != null) {
callback.sendFailure(e);
callback.onFailure(e);
}
return false;
} finally {
//Make sure we close the payload stream, if any
InputStream stream = np.getPayload();
@@ -244,14 +244,14 @@ public class LanLink extends BaseLink {
//Blocking, do not call from main thread
@Override
public void sendPackage(NetworkPackage np,Device.SendPackageStatusCallback callback) {
sendPackageInternal(np, callback, null);
public boolean sendPackage(NetworkPackage np,Device.SendPackageStatusCallback callback) {
return sendPackageInternal(np, callback, null);
}
//Blocking, do not call from main thread
@Override
public void sendPackageEncrypted(NetworkPackage np, Device.SendPackageStatusCallback callback, PublicKey key) {
sendPackageInternal(np, callback, key);
public boolean sendPackageEncrypted(NetworkPackage np, Device.SendPackageStatusCallback callback, PublicKey key) {
return sendPackageInternal(np, callback, key);
}
private void receivedNetworkPackage(NetworkPackage np) {

View File

@@ -31,6 +31,7 @@ import org.kde.kdeconnect.Backends.BaseLinkProvider;
import org.kde.kdeconnect.BackgroundService;
import org.kde.kdeconnect.Device;
import org.kde.kdeconnect.Helpers.DeviceHelper;
import org.kde.kdeconnect.Helpers.NetworkHelper;
import org.kde.kdeconnect.Helpers.SecurityHelpers.SslHelper;
import org.kde.kdeconnect.Helpers.StringsHelper;
import org.kde.kdeconnect.NetworkPackage;
@@ -68,18 +69,18 @@ public class LanLinkProvider extends BaseLinkProvider implements LanLink.LinkDis
final static int MAX_PORT = 1764;
final static int PAYLOAD_TRANSFER_MIN_PORT = 1739;
private final Context context;
final Context context;
private final HashMap<String, LanLink> visibleComputers = new HashMap<>(); //Links by device id
private ServerSocket tcpServer;
ServerSocket tcpServer;
private DatagramSocket udpServer;
private DatagramSocket udpServerOldPort;
private boolean listening = false;
boolean listening = false;
// To prevent infinte loop between Android < IceCream because both device can only broadcast identity package but cannot connect via TCP
private ArrayList<InetAddress> reverseConnectionBlackList = new ArrayList<>();
ArrayList<InetAddress> reverseConnectionBlackList = new ArrayList<>();
@Override // SocketClosedCallback
public void linkDisconnected(LanLink brokenLink) {
@@ -89,7 +90,7 @@ public class LanLinkProvider extends BaseLinkProvider implements LanLink.LinkDis
}
//They received my UDP broadcast and are connecting to me. The first thing they sned should be their identity.
public void tcpPackageReceived(Socket socket) throws Exception {
void tcpPackageReceived(Socket socket) throws Exception {
NetworkPackage networkPackage;
try {
@@ -112,7 +113,7 @@ public class LanLinkProvider extends BaseLinkProvider implements LanLink.LinkDis
}
//I've received their broadcast and should connect to their TCP socket and send my identity.
protected void udpPacketReceived(DatagramPacket packet) throws Exception {
void udpPacketReceived(DatagramPacket packet) throws Exception {
final InetAddress address = packet.getAddress();
@@ -171,7 +172,7 @@ public class LanLinkProvider extends BaseLinkProvider implements LanLink.LinkDis
}
}
private void configureSocket(Socket socket) {
void configureSocket(Socket socket) {
try {
socket.setKeepAlive(true);
} catch (SocketException e) {
@@ -360,7 +361,12 @@ public class LanLinkProvider extends BaseLinkProvider implements LanLink.LinkDis
throw new IOException("No ports available");
}
void broadcastUdpPackage() {
private void broadcastUdpPackage() {
if (NetworkHelper.isOnMobileNetwork(context)) {
Log.w("LanLinkProvider", "On 3G network, not sending broadcast.");
return;
}
new Thread(new Runnable() {
@Override

View File

@@ -39,7 +39,7 @@ import java.util.TimerTask;
public class LanPairingHandler extends BasePairingHandler {
private Timer mPairingTimer;
Timer mPairingTimer;
public LanPairingHandler(Device device, final PairingHandlerCallback callback) {
super(device, callback);
@@ -142,7 +142,7 @@ public class LanPairingHandler extends BasePairingHandler {
Device.SendPackageStatusCallback statusCallback = new Device.SendPackageStatusCallback() {
@Override
protected void onSuccess() {
public void onSuccess() {
hidePairingNotification(); //Will stop the pairingTimer if it was running
mPairingTimer = new Timer();
mPairingTimer.schedule(new TimerTask() {
@@ -157,14 +157,19 @@ public class LanPairingHandler extends BasePairingHandler {
}
@Override
protected void onFailure(Throwable e) {
public void onFailure(Throwable e) {
if (e != null) {
e.printStackTrace();
} else {
Log.e("LanPairing/onFailure", "Unknown (null) exception");
}
mCallback.pairingFailed(mDevice.getContext().getString(R.string.error_could_not_send_package));
}
};
mDevice.sendPackage(createPairPackage(), statusCallback);
}
public void hidePairingNotification() {
void hidePairingNotification() {
mDevice.hidePairingNotification();
if (mPairingTimer != null) {
mPairingTimer .cancel();
@@ -176,12 +181,17 @@ public class LanPairingHandler extends BasePairingHandler {
hidePairingNotification();
Device.SendPackageStatusCallback statusCallback = new Device.SendPackageStatusCallback() {
@Override
protected void onSuccess() {
public void onSuccess() {
pairingDone();
}
@Override
protected void onFailure(Throwable e) {
public void onFailure(Throwable e) {
if (e != null) {
e.printStackTrace();
} else {
Log.e("LanPairing/onFailure", "Unknown (null) exception");
}
mCallback.pairingFailed(mDevice.getContext().getString(R.string.error_not_reachable));
}
};
@@ -197,7 +207,7 @@ public class LanPairingHandler extends BasePairingHandler {
mDevice.sendPackage(np);
}
public void pairingDone() {
void pairingDone() {
// Store device information needed to create a Device object in a future
//Log.e("KDE/PairingDone", "Pairing Done");
SharedPreferences.Editor editor = mDevice.getContext().getSharedPreferences(mDevice.getDeviceId(), Context.MODE_PRIVATE).edit();

View File

@@ -47,18 +47,19 @@ public class LoopbackLink extends BaseLink {
}
@Override
public void sendPackage(NetworkPackage in, Device.SendPackageStatusCallback callback) {
public boolean sendPackage(NetworkPackage in, Device.SendPackageStatusCallback callback) {
packageReceived(in);
if (in.hasPayload()) {
callback.sendProgress(0);
callback.onProgressChanged(0);
in.setPayload(in.getPayload(), in.getPayloadSize());
callback.sendProgress(100);
callback.onProgressChanged(100);
}
callback.sendSuccess();
callback.onSuccess();
return true;
}
@Override
public void sendPackageEncrypted(NetworkPackage np, Device.SendPackageStatusCallback callback, PublicKey key) {
sendPackage(np, callback);
public boolean sendPackageEncrypted(NetworkPackage np, Device.SendPackageStatusCallback callback, PublicKey key) {
return sendPackage(np, callback);
}
}

View File

@@ -27,7 +27,6 @@ import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.os.Binder;
import android.os.IBinder;
import android.preference.PreferenceManager;
import android.util.Log;
import org.kde.kdeconnect.Backends.BaseLink;
@@ -120,7 +119,7 @@ public class BackgroundService extends Service {
}
};
private void onDeviceListChanged() {
public void onDeviceListChanged() {
for(DeviceListChangedCallback callback : deviceListChangedCallbacks.values()) {
callback.onDeviceListChanged();
}

View File

@@ -37,6 +37,7 @@ import android.util.Log;
import org.kde.kdeconnect.Backends.BaseLink;
import org.kde.kdeconnect.Backends.BasePairingHandler;
import org.kde.kdeconnect.Backends.LanBackend.LanLinkProvider;
import org.kde.kdeconnect.Helpers.NotificationHelper;
import org.kde.kdeconnect.Helpers.SecurityHelpers.SslHelper;
import org.kde.kdeconnect.Plugins.Plugin;
import org.kde.kdeconnect.Plugins.PluginFactory;
@@ -367,7 +368,23 @@ public class Device implements BaseLink.PackageReceiver {
Intent intent = new Intent(getContext(), MaterialActivity.class);
intent.putExtra("deviceId", getDeviceId());
intent.putExtra("notificationId", notificationId);
PendingIntent pendingIntent = PendingIntent.getActivity(getContext(), 0, intent, PendingIntent.FLAG_ONE_SHOT);
PendingIntent pendingIntent = PendingIntent.getActivity(getContext(), 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
Intent acceptIntent = new Intent(getContext(), MaterialActivity.class);
Intent rejectIntent = new Intent(getContext(), MaterialActivity.class);
acceptIntent.putExtra("deviceId", getDeviceId());
acceptIntent.putExtra("notificationId", notificationId);
acceptIntent.setAction("action "+System.currentTimeMillis());
acceptIntent.putExtra(MaterialActivity.PAIR_REQUEST_STATUS, MaterialActivity.PAIRING_ACCEPTED);
rejectIntent.putExtra("deviceId", getDeviceId());
rejectIntent.putExtra("notificationId", notificationId);
rejectIntent.setAction("action "+System.currentTimeMillis());
rejectIntent.putExtra(MaterialActivity.PAIR_REQUEST_STATUS, MaterialActivity.PAIRING_REJECTED);
PendingIntent acceptedPendingIntent = PendingIntent.getActivity(getContext(), 2, acceptIntent, PendingIntent.FLAG_ONE_SHOT);
PendingIntent rejectedPendingIntent = PendingIntent.getActivity(getContext(), 4, rejectIntent, PendingIntent.FLAG_ONE_SHOT);
Resources res = getContext().getResources();
@@ -377,19 +394,16 @@ public class Device implements BaseLink.PackageReceiver {
.setContentIntent(pendingIntent)
.setTicker(res.getString(R.string.pair_requested))
.setSmallIcon(R.drawable.ic_notification)
.addAction(R.drawable.ic_accept_pairing, res.getString(R.string.pairing_accept), acceptedPendingIntent)
.addAction(R.drawable.ic_reject_pairing, res.getString(R.string.pairing_reject), rejectedPendingIntent)
.setAutoCancel(true)
.setDefaults(Notification.DEFAULT_ALL)
.build();
final NotificationManager notificationManager = (NotificationManager) getContext().getSystemService(Context.NOTIFICATION_SERVICE);
NotificationHelper.notifyCompat(notificationManager, notificationId, noti);
try {
BackgroundService.addGuiInUseCounter(context);
notificationManager.notify(notificationId, noti);
} catch(Exception e) {
//4.1 will throw an exception about not having the VIBRATE permission, ignore it.
//https://android.googlesource.com/platform/frameworks/base/+/android-4.2.1_r1.2%5E%5E!/
}
BackgroundService.addGuiInUseCounter(context);
}
public void hidePairingNotification() {
@@ -582,42 +596,43 @@ public class Device implements BaseLink.PackageReceiver {
}
public static abstract class SendPackageStatusCallback {
protected abstract void onSuccess();
protected abstract void onFailure(Throwable e);
protected void onProgressChanged(int percent) { }
public abstract void onSuccess();
public abstract void onFailure(Throwable e);
public void onProgressChanged(int percent) { }
}
private boolean success = false;
public void sendSuccess() {
success = true;
onSuccess();
}
public void sendFailure(Throwable e) {
private SendPackageStatusCallback defaultCallback = new SendPackageStatusCallback() {
@Override
public void onSuccess() { }
@Override
public void onFailure(Throwable e) {
if (e != null) {
e.printStackTrace();
Log.e("KDE/sendPackage", "Exception: " + e.getMessage());
} else {
Log.e("KDE/sendPackage", "Unknown (null) exception");
}
onFailure(e);
}
public void sendProgress(int percent) { onProgressChanged(percent); }
}
};
public void sendPackage(NetworkPackage np) {
sendPackage(np,new SendPackageStatusCallback() {
@Override
protected void onSuccess() { }
@Override
protected void onFailure(Throwable e) { }
});
sendPackage(np, defaultCallback);
}
public boolean sendPackageBlocking(NetworkPackage np) {
return sendPackageBlocking(np, defaultCallback);
}
//Async
public void sendPackage(final NetworkPackage np, final SendPackageStatusCallback callback) {
new Thread(new Runnable() {
@Override
public void run() {
sendPackageBlocking(np, callback);
}
}).start();
}
hackToMakeRetrocompatiblePacketTypes(np);
public boolean sendPackageBlocking(final NetworkPackage np, final SendPackageStatusCallback callback) {
/*
if (!m_outgoingCapabilities.contains(np.getType()) && !NetworkPackage.protocolPackageTypes.contains(np.getType())) {
@@ -626,37 +641,29 @@ public class Device implements BaseLink.PackageReceiver {
}
*/
//Log.e("sendPackage", "Sending package...");
//Log.e("sendPackage", np.serialize());
hackToMakeRetrocompatiblePacketTypes(np);
final Throwable backtrace = new Throwable();
new Thread(new Runnable() {
@Override
public void run() {
boolean useEncryption = (protocolVersion < LanLinkProvider.MIN_VERSION_WITH_SSL_SUPPORT && (!np.getType().equals(NetworkPackage.PACKAGE_TYPE_PAIR) && isPaired()));
//Make a copy to avoid concurrent modification exception if the original list changes
for (final BaseLink link : links) {
if (link == null) continue; //Since we made a copy, maybe somebody destroyed the link in the meanwhile
if (useEncryption) {
link.sendPackageEncrypted(np, callback, publicKey);
} else {
link.sendPackage(np, callback);
}
if (callback.success) break; //If the link didn't call sendSuccess(), try the next one
}
if (!callback.success) {
Log.e("KDE/sendPackage", "No device link (of "+links.size()+" available) could send the package. Package "+np.getType()+" to " + name + " lost!");
backtrace.printStackTrace();
}
boolean useEncryption = (protocolVersion < LanLinkProvider.MIN_VERSION_WITH_SSL_SUPPORT && (!np.getType().equals(NetworkPackage.PACKAGE_TYPE_PAIR) && isPaired()));
boolean success = false;
//Make a copy to avoid concurrent modification exception if the original list changes
for (final BaseLink link : links) {
if (link == null) continue; //Since we made a copy, maybe somebody destroyed the link in the meanwhile
if (useEncryption) {
success = link.sendPackageEncrypted(np, callback, publicKey);
} else {
success = link.sendPackage(np, callback);
}
}).start();
if (success) break; //If the link didn't call sendSuccess(), try the next one
}
if (!success) {
Log.e("KDE/sendPackage", "No device link (of "+links.size()+" available) could send the package. Package "+np.getType()+" to " + name + " lost!");
}
return success;
}
//
// Plugin-related functions
//

View File

@@ -450,13 +450,17 @@ public class DeviceHelper {
public static String getAndroidDeviceName() {
String deviceName = null;
try {
String dictName = humanReadableNames.get(Build.MODEL.replace(' ', '_'));
String internalName = Build.MODEL.replace(' ', '_');
String dictName = humanReadableNames.get(internalName);
if (dictName != null) {
deviceName = dictName;
} else if (Build.BRAND.equalsIgnoreCase("samsung")) {
deviceName = "Samsung " + Build.MODEL;
} else {
deviceName = Build.BRAND;
Log.w("getAndroidDeviceName", "Not found human readable name for device '" + internalName + "'");
if (Build.BRAND.equalsIgnoreCase("samsung")) {
deviceName = "Samsung " + Build.MODEL;
} else {
deviceName = Build.BRAND;
}
}
} catch (Exception e) {
//Some phones might not define BRAND or MODEL, ignore exceptions

View File

@@ -27,17 +27,35 @@ import java.io.File;
public class FilesHelper {
public static String getFileExt(String fileName) {
//return MimeTypeMap.getFileExtensionFromUrl(fileName);
return fileName.substring((fileName.lastIndexOf(".") + 1), fileName.length());
public static String getFileExt(String filename) {
//return MimeTypeMap.getFileExtensionFromUrl(filename);
return filename.substring((filename.lastIndexOf(".") + 1));
}
public static String getFileNameWithoutExt(String filename) {
int dot = filename.lastIndexOf(".");
return (dot < 0)? filename : filename.substring(0, dot);
}
public static String getMimeTypeFromFile(String file) {
String mime = MimeTypeMap.getSingleton().getMimeTypeFromExtension(getFileExt(file));
if (mime == null) mime = "*/*";
return mime;
}
public static String findNonExistingNameForNewFile(String path, String filename) {
int dot = filename.lastIndexOf(".");
String name = (dot < 0)? filename : filename.substring(0, dot);
String ext = (dot < 0)? "" : filename.substring(filename.lastIndexOf("."));
int num = 1;
while (new File(path+"/"+filename).exists()) {
filename = name+" ("+num+")"+ext;
num++;
}
return filename;
}
//Following code from http://activemq.apache.org/maven/5.7.0/kahadb/apidocs/src-html/org/apache/kahadb/util/IOHelper.html
/**
* Converts any string into a string that is safe to use as a file name.

View File

@@ -0,0 +1,17 @@
package org.kde.kdeconnect.Helpers;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
public class MediaStoreHelper {
//Maybe this class could batch successive calls together
public static void indexFile(Context context, Uri path) {
Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
mediaScanIntent.setData(path);
context.sendBroadcast(mediaScanIntent);
}
}

View File

@@ -0,0 +1,53 @@
package org.kde.kdeconnect.Helpers;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.Network;
import android.net.NetworkInfo;
import android.util.Log;
import java.io.FileReader;
import java.io.LineNumberReader;
public class NetworkHelper {
public static boolean isOnMobileNetwork(Context context) {
if (context == null) {
return false;
}
if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.LOLLIPOP) {
return false; //No good way to know it
}
boolean mobile = false;
final ConnectivityManager connMgr = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
Network[] networks = connMgr.getAllNetworks();
for (Network network : networks) {
NetworkInfo info = connMgr.getNetworkInfo(network);
if (info == null) {
continue;
}
if (info.getType() == ConnectivityManager.TYPE_MOBILE) {
mobile = info.isConnected();
continue;
}
//Log.e(info.getTypeName(),""+info.isAvailable());
if (info.isAvailable()) return false; //We are connected to at least one non-mobile network
}
if (mobile) { //We suspect we are on a mobile net
try {
//Check the number of network neighbours, on data it should be 0
LineNumberReader is = new LineNumberReader(new FileReader("/proc/net/arp"));
is.skip(Long.MAX_VALUE);
//Log.e("NetworkHelper", "procnetarp has " + is.getLineNumber() + " lines");
if (is.getLineNumber() > 1) { //The first line are the headers
return false; //I have neighbours, so this doesn't look like a mobile network
}
} catch (Exception e) {
Log.e("NetworkHelper", "Exception reading procnetarp");
e.printStackTrace();
}
}
return false;
}
}

View File

@@ -0,0 +1,25 @@
package org.kde.kdeconnect.Helpers;
import android.app.Notification;
import android.app.NotificationManager;
public class NotificationHelper {
public static void notifyCompat(NotificationManager notificationManager, int notificationId, Notification notification) {
try {
notificationManager.notify(notificationId, notification);
} catch(Exception e) {
//4.1 will throw an exception about not having the VIBRATE permission, ignore it.
//https://android.googlesource.com/platform/frameworks/base/+/android-4.2.1_r1.2%5E%5E!/
}
}
public static void notifyCompat(NotificationManager notificationManager, String tag, int notificationId, Notification notification) {
try {
notificationManager.notify(tag, notificationId, notification);
} catch(Exception e) {
//4.1 will throw an exception about not having the VIBRATE permission, ignore it.
//https://android.googlesource.com/platform/frameworks/base/+/android-4.2.1_r1.2%5E%5E!/
}
}
}

View File

@@ -67,6 +67,7 @@ public class KdeConnectBroadcastReceiver extends BroadcastReceiver
BackgroundService.RunCommand(context, new BackgroundService.InstanceCallback() {
@Override
public void onServiceStart(BackgroundService service) {
service.onDeviceListChanged();
service.onNetworkChange();
}
});

View File

@@ -8,6 +8,7 @@ import android.media.Ringtone;
import android.media.RingtoneManager;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
@@ -20,7 +21,12 @@ public class FindMyPhoneActivity extends Activity {
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
finish(); //If this activity was already open and we received the ring packet again, just finish it
if(ringtone != null) {
// If this activity was already open and we received the ring packet again, just finish it
finish();
}
// otherwise the activity will become active again
}
@Override
@@ -33,8 +39,28 @@ public class FindMyPhoneActivity extends Activity {
WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED |
WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON);
findViewById(R.id.bFindMyPhone).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
finish();
}
});
}
@Override
protected void onStart() {
super.onStart();
Uri ringtoneUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_RINGTONE);
ringtone = RingtoneManager.getRingtone(getApplicationContext(), ringtoneUri);
if (ringtone == null) {
ringtoneUri = RingtoneManager.getValidRingtoneUri(getApplicationContext());
if (ringtoneUri == null) {
Log.e("FindMyPhone", "Could not find a ringtone to play!");
return;
}
ringtone = RingtoneManager.getRingtone(getApplicationContext(), ringtoneUri);
}
if (android.os.Build.VERSION.SDK_INT >= 21) {
AudioAttributes.Builder b = new AudioAttributes.Builder();
@@ -45,18 +71,16 @@ public class FindMyPhoneActivity extends Activity {
}
ringtone.play();
findViewById(R.id.bFindMyPhone).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
finish();
}
});
}
@Override
public void finish() {
ringtone.stop();
super.finish();
protected void onStop() {
super.onStop();
if(ringtone != null) {
ringtone.stop();
ringtone = null;
}
}
}

View File

@@ -21,7 +21,6 @@
package org.kde.kdeconnect.Plugins.MprisPlugin;
import android.content.SharedPreferences;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
@@ -34,7 +33,6 @@ import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.SeekBar;
import android.widget.Spinner;
import android.widget.TextView;
@@ -95,22 +93,16 @@ public class MprisActivity extends ActionBarActivity {
TextView nowPlaying = (TextView) findViewById(R.id.now_playing_textview);
if (!nowPlaying.getText().toString().equals(song)) {
nowPlaying.setText(song);
Bitmap currentArt = mpris.getCurrentArt();
ImageView artView = (ImageView) findViewById(R.id.artImageView);
if (currentArt != null) {
artView.setImageBitmap(currentArt);
}
}
if (mpris.getLength() > -1 && mpris.getPosition() > -1 && !"spotify".equals(mpris.getPlayer().toLowerCase())) {
((TextView) findViewById(R.id.time_textview)).setText(milisToProgress(mpris.getLength()));
//Hacks for Spotify because it reports incorrect info about what it supports
boolean isSpotify = "spotify".equals(mpris.getPlayer().toLowerCase());
if (mpris.getLength() > -1 && mpris.getPosition() > -1 && !isSpotify) {
((TextView) findViewById(R.id.time_textview)).setText(milisToProgress(mpris.getLength()));
SeekBar positionSeek = (SeekBar)findViewById(R.id.positionSeek);
positionSeek.setMax((int)(mpris.getLength()));
positionSeek.setProgress((int)(mpris.getPosition()));
findViewById(R.id.progress_slider).setVisibility(View.VISIBLE);
} else {
findViewById(R.id.progress_slider).setVisibility(View.GONE);
@@ -122,9 +114,23 @@ public class MprisActivity extends ActionBarActivity {
boolean isPlaying = mpris.isPlaying();
if (isPlaying) {
((ImageButton) findViewById(R.id.play_button)).setImageResource(android.R.drawable.ic_media_pause);
findViewById(R.id.play_button).setVisibility(mpris.isPauseAllowed() ? View.VISIBLE : View.GONE);
} else {
((ImageButton) findViewById(R.id.play_button)).setImageResource(android.R.drawable.ic_media_play);
findViewById(R.id.play_button).setVisibility(mpris.isPlayAllowed() ? View.VISIBLE : View.GONE);
}
if (isSpotify) {
findViewById(R.id.volume_layout).setVisibility(View.INVISIBLE);
findViewById(R.id.rew_button).setVisibility(View.GONE);
findViewById(R.id.ff_button).setVisibility(View.GONE);
} else {
findViewById(R.id.volume_layout).setVisibility(View.VISIBLE);
findViewById(R.id.rew_button).setVisibility(mpris.isSeekAllowed() ? View.VISIBLE : View.GONE);
findViewById(R.id.ff_button).setVisibility(mpris.isSeekAllowed() ? View.VISIBLE : View.GONE);
}
findViewById(R.id.next_button).setVisibility(mpris.isGoNextAllowed() ? View.VISIBLE : View.GONE);
findViewById(R.id.prev_button).setVisibility(mpris.isGoPreviousAllowed() ? View.VISIBLE : View.GONE);
}
});
}
@@ -162,23 +168,16 @@ public class MprisActivity extends ActionBarActivity {
if (pos >= playerList.size()) return;
((TextView) findViewById(R.id.now_playing_textview)).setText("");
String player = playerList.get(pos);
mpris.setPlayer(player);
//Spotify doesn't support changing the volume yet...
//Also doesn't support seeking and telling actual position...
if (player.toLowerCase().equals("spotify")) {
findViewById(R.id.volume_layout).setVisibility(View.INVISIBLE);
findViewById(R.id.rew_button).setVisibility(View.GONE);
findViewById(R.id.ff_button).setVisibility(View.GONE);
findViewById(R.id.positionSeek).setVisibility(View.INVISIBLE);
findViewById(R.id.progress_slider).setVisibility(View.GONE);
} else {
findViewById(R.id.volume_layout).setVisibility(View.VISIBLE);
findViewById(R.id.rew_button).setVisibility(View.VISIBLE);
findViewById(R.id.ff_button).setVisibility(View.VISIBLE);
findViewById(R.id.positionSeek).setVisibility(View.VISIBLE);
if (player.equals(mpris.getPlayer())) {
return; //Player hasn't actually changed
}
mpris.setPlayer(player);
//Clear values from previous player
((TextView) findViewById(R.id.now_playing_textview)).setText("");
((TextView) findViewById(R.id.time_textview)).setText(milisToProgress(0));
((SeekBar)findViewById(R.id.positionSeek)).setMax(0);
}
@Override

View File

@@ -22,13 +22,10 @@ package org.kde.kdeconnect.Plugins.MprisPlugin;
import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.Message;
import android.support.v4.content.ContextCompat;
import android.util.Base64;
import android.util.Log;
import org.kde.kdeconnect.NetworkPackage;
@@ -47,11 +44,15 @@ public class MprisPlugin extends Plugin {
private String player = "";
private boolean playing = false;
private String currentSong = "";
private Bitmap currentArt;
private int volume = 50;
private long length = -1;
private long lastPosition;
private long lastPositionTime;
private boolean playAllowed = true;
private boolean pauseAllowed = true;
private boolean goNextAllowed = true;
private boolean goPreviousAllowed = true;
private boolean seekAllowed = true;
private HashMap<String,Handler> playerStatusUpdated = new HashMap<>();
private List<String> playerList = new ArrayList<>();
@@ -125,8 +126,7 @@ public class MprisPlugin extends Plugin {
@Override
public boolean onPackageReceived(NetworkPackage np) {
if (np.has("nowPlaying") || np.has("volume") || np.has("isPlaying") || np.has("length") ||
np.has("pos") || np.has("artImage")) {
if (np.has("nowPlaying") || np.has("volume") || np.has("isPlaying") || np.has("length") || np.has("pos")) {
if (np.getString("player").equals(player)) {
currentSong = np.getString("nowPlaying", currentSong);
volume = np.getInt("volume", volume);
@@ -135,12 +135,12 @@ public class MprisPlugin extends Plugin {
lastPosition = np.getLong("pos", lastPosition);
lastPositionTime = System.currentTimeMillis();
}
if (np.has("artImage")) {
String base64Image = np.getString("artImage");
byte[] decodedBytes = Base64.decode(base64Image, 0);
currentArt = BitmapFactory.decodeByteArray(decodedBytes, 0, decodedBytes.length);
}
playing = np.getBoolean("isPlaying", playing);
playAllowed = np.getBoolean("canPlay", playAllowed);
pauseAllowed = np.getBoolean("canPause", pauseAllowed);
goNextAllowed = np.getBoolean("canGoNext", goNextAllowed);
goPreviousAllowed = np.getBoolean("canGoPrevious", goPreviousAllowed);
seekAllowed = np.getBoolean("canSeek", seekAllowed);
for (String key : playerStatusUpdated.keySet()) {
try {
playerStatusUpdated.get(key).dispatchMessage(new Message());
@@ -218,9 +218,13 @@ public class MprisPlugin extends Plugin {
if (player == null || player.equals(this.player)) return;
this.player = player;
currentSong = "";
currentArt = null;
volume = 50;
playing = false;
playAllowed = true;
pauseAllowed = true;
goNextAllowed = true;
goPreviousAllowed = true;
seekAllowed = true;
for (String key : playerStatusUpdated.keySet()) {
try {
playerStatusUpdated.get(key).dispatchMessage(new Message());
@@ -241,8 +245,6 @@ public class MprisPlugin extends Plugin {
return currentSong;
}
public Bitmap getCurrentArt() { return currentArt; }
public String getPlayer() {
return player;
}
@@ -257,6 +259,26 @@ public class MprisPlugin extends Plugin {
return playing;
}
public boolean isPlayAllowed() {
return playAllowed;
}
public boolean isPauseAllowed() {
return pauseAllowed;
}
public boolean isGoNextAllowed() {
return goNextAllowed;
}
public boolean isGoPreviousAllowed() {
return goPreviousAllowed;
}
public boolean isSeekAllowed() {
return seekAllowed;
}
public long getPosition(){
if(playing) {
return lastPosition + (System.currentTimeMillis() - lastPositionTime);

View File

@@ -224,7 +224,7 @@ public class NotificationsPlugin extends Plugin implements NotificationReceiver.
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
try {
Bundle extras = notification.extras;
String extraTitle = extras.getString(TITLE_KEY);
String extraTitle = extras.getCharSequence(TITLE_KEY).toString();
String extraText = null;
Object extraTextExtra = extras.get(TEXT_KEY);
if (extraTextExtra != null) extraText = extraTextExtra.toString();

View File

@@ -30,6 +30,7 @@ import android.support.v4.app.NotificationCompat;
import android.support.v4.app.TaskStackBuilder;
import android.util.Log;
import org.kde.kdeconnect.Helpers.NotificationHelper;
import org.kde.kdeconnect.NetworkPackage;
import org.kde.kdeconnect.Plugins.Plugin;
import org.kde.kdeconnect.UserInterface.MaterialActivity;
@@ -89,12 +90,7 @@ public class PingPlugin extends Plugin {
.build();
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
try {
notificationManager.notify(id, noti);
} catch(Exception e) {
//4.1 will throw an exception about not having the VIBRATE permission, ignore it.
//https://android.googlesource.com/platform/frameworks/base/+/android-4.2.1_r1.2%5E%5E!/
}
NotificationHelper.notifyCompat(notificationManager, id, noti);
return true;

View File

@@ -161,8 +161,9 @@ public abstract class Plugin {
public void onDestroy() { }
/**
* If onCreate returns false, should create a dialog explaining
* the problem (and how to fix it, if possible) to the user.
* Called when a plugin receives a package. By convention we return true
* when we have done something in response to the package or false
* otherwise, even though that value is unused as of now.
*/
public boolean onPackageReceived(NetworkPackage np) { return false; }

View File

@@ -33,6 +33,7 @@ import org.kde.kdeconnect.Plugins.MprisPlugin.MprisPlugin;
import org.kde.kdeconnect.Plugins.NotificationsPlugin.NotificationsPlugin;
import org.kde.kdeconnect.Plugins.PingPlugin.PingPlugin;
import org.kde.kdeconnect.Plugins.ReceiveNotificationsPlugin.ReceiveNotificationsPlugin;
import org.kde.kdeconnect.Plugins.RemoteKeyboardPlugin.RemoteKeyboardPlugin;
import org.kde.kdeconnect.Plugins.RunCommandPlugin.RunCommandPlugin;
import org.kde.kdeconnect.Plugins.SftpPlugin.SftpPlugin;
import org.kde.kdeconnect.Plugins.SharePlugin.SharePlugin;
@@ -124,6 +125,8 @@ public class PluginFactory {
PluginFactory.registerPlugin(TelepathyPlugin.class);
PluginFactory.registerPlugin(FindMyPhonePlugin.class);
PluginFactory.registerPlugin(RunCommandPlugin.class);
//Commented here and in AndroidManifest until we release a desktop version with this feature, so we don't get bad "feature not working" reviews
//PluginFactory.registerPlugin(RemoteKeyboardPlugin.class);
}
public static PluginInfo getPluginInfo(Context context, String pluginKey) {

View File

@@ -32,6 +32,7 @@ import android.support.v4.app.NotificationCompat;
import android.support.v4.app.TaskStackBuilder;
import android.util.Log;
import org.kde.kdeconnect.Helpers.NotificationHelper;
import org.kde.kdeconnect.NetworkPackage;
import org.kde.kdeconnect.Plugins.Plugin;
import org.kde.kdeconnect.UserInterface.MaterialActivity;
@@ -114,13 +115,8 @@ public class ReceiveNotificationsPlugin extends Plugin {
.build();
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
try {
// tag all incoming notifications
notificationManager.notify("kdeconnectId:" + np.getString("id", "0"), np.getInt("id", 0), noti);
} catch (Exception e) {
//4.1 will throw an exception about not having the VIBRATE permission, ignore it.
//https://android.googlesource.com/platform/frameworks/base/+/android-4.2.1_r1.2%5E%5E!/
}
NotificationHelper.notifyCompat(notificationManager, "kdeconnectId:" + np.getString("id", "0"), np.getInt("id", 0), noti);
}
return true;

View File

@@ -0,0 +1,398 @@
/*
* Copyright 2017 Holger Kaelberer <holger.k@elberer.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License or (at your option) version 3 or any later version
* accepted by the membership of KDE e.V. (or its successor approved
* by the membership of KDE e.V.), which shall act as a proxy
* defined in Section 14 of version 3 of the license.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.kde.kdeconnect.Plugins.RemoteKeyboardPlugin;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.SystemClock;
import android.preference.PreferenceManager;
import android.support.v4.content.ContextCompat;
import android.support.v4.util.Pair;
import android.util.Log;
import android.util.SparseIntArray;
import android.view.KeyEvent;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.ExtractedText;
import android.view.inputmethod.ExtractedTextRequest;
import android.view.inputmethod.InputConnection;
import org.kde.kdeconnect.NetworkPackage;
import org.kde.kdeconnect.Plugins.Plugin;
import org.kde.kdeconnect_tp.R;
import java.util.ArrayList;
import java.util.concurrent.locks.ReentrantLock;
public class RemoteKeyboardPlugin extends Plugin {
public final static String PACKAGE_TYPE_MOUSEPAD_REQUEST = "kdeconnect.mousepad.request";
public final static String PACKAGE_TYPE_MOUSEPAD_ECHO = "kdeconnect.mousepad.echo";
public final static String PACKAGE_TYPE_MOUSEPAD_KEYBOARDSTATE = "kdeconnect.mousepad.keyboardstate";
/**
* Track and expose plugin instances to allow for a 'connected'-indicator in the IME:
*/
private static ArrayList<RemoteKeyboardPlugin> instances = new ArrayList<RemoteKeyboardPlugin>();
private static ReentrantLock instancesLock = new ReentrantLock(true);
public static ArrayList<RemoteKeyboardPlugin> getInstances() {
return instances;
}
public static ArrayList<RemoteKeyboardPlugin> acquireInstances() {
instancesLock.lock();
return getInstances();
}
public static ArrayList<RemoteKeyboardPlugin> releaseInstances() {
instancesLock.unlock();
return getInstances();
}
public static boolean isConnected() {
return instances.size() > 0;
}
private static SparseIntArray specialKeyMap = new SparseIntArray();
static {
int i = 0;
specialKeyMap.put(++i, KeyEvent.KEYCODE_DEL); // 1
specialKeyMap.put(++i, KeyEvent.KEYCODE_TAB); // 2
++i; //specialKeyMap.put(++i, KeyEvent.KEYCODE_ENTER, 12); // 3 is not used
specialKeyMap.put(++i, KeyEvent.KEYCODE_DPAD_LEFT); // 4
specialKeyMap.put(++i, KeyEvent.KEYCODE_DPAD_UP); // 5
specialKeyMap.put(++i, KeyEvent.KEYCODE_DPAD_RIGHT); // 6
specialKeyMap.put(++i, KeyEvent.KEYCODE_DPAD_DOWN); // 7
specialKeyMap.put(++i, KeyEvent.KEYCODE_PAGE_UP); // 8
specialKeyMap.put(++i, KeyEvent.KEYCODE_PAGE_DOWN); // 9
if (Build.VERSION.SDK_INT >= 11) {
specialKeyMap.put(++i, KeyEvent.KEYCODE_MOVE_HOME); // 10
specialKeyMap.put(++i, KeyEvent.KEYCODE_MOVE_END); // 11
specialKeyMap.put(++i, KeyEvent.KEYCODE_ENTER); // 12
specialKeyMap.put(++i, KeyEvent.KEYCODE_FORWARD_DEL); // 13
specialKeyMap.put(++i, KeyEvent.KEYCODE_ESCAPE); // 14
specialKeyMap.put(++i, KeyEvent.KEYCODE_SYSRQ); // 15
specialKeyMap.put(++i, KeyEvent.KEYCODE_SCROLL_LOCK); // 16
++i; // 17
++i; // 18
++i; // 19
++i; // 20
specialKeyMap.put(++i, KeyEvent.KEYCODE_F1); // 21
specialKeyMap.put(++i, KeyEvent.KEYCODE_F2); // 22
specialKeyMap.put(++i, KeyEvent.KEYCODE_F3); // 23
specialKeyMap.put(++i, KeyEvent.KEYCODE_F4); // 24
specialKeyMap.put(++i, KeyEvent.KEYCODE_F5); // 25
specialKeyMap.put(++i, KeyEvent.KEYCODE_F6); // 26
specialKeyMap.put(++i, KeyEvent.KEYCODE_F7); // 27
specialKeyMap.put(++i, KeyEvent.KEYCODE_F8); // 28
specialKeyMap.put(++i, KeyEvent.KEYCODE_F9); // 29
specialKeyMap.put(++i, KeyEvent.KEYCODE_F10); // 30
specialKeyMap.put(++i, KeyEvent.KEYCODE_F11); // 31
specialKeyMap.put(++i, KeyEvent.KEYCODE_F12); // 21
}
}
@Override
public boolean onCreate() {
Log.d("RemoteKeyboardPlugin", "Creating for device " + device.getName());
acquireInstances();
try {
instances.add(this);
} finally {
releaseInstances();
}
if (RemoteKeyboardService.instance != null)
RemoteKeyboardService.instance.handler.post(new Runnable() {
@Override
public void run() {
RemoteKeyboardService.instance.updateInputView();
}
});
return true;
}
@Override
public void onDestroy() {
acquireInstances();
try {
if (instances.contains(this)) {
instances.remove(this);
if (instances.size() < 1 && RemoteKeyboardService.instance != null)
RemoteKeyboardService.instance.handler.post(new Runnable() {
@Override
public void run() {
RemoteKeyboardService.instance.updateInputView();
}
});
}
} finally {
releaseInstances();
}
Log.d("RemoteKeyboardPlugin", "Destroying for device " + device.getName());
}
@Override
public String getDisplayName() {
return context.getString(R.string.pref_plugin_remotekeyboard);
}
@Override
public String getDescription() {
return context.getString(R.string.pref_plugin_remotekeyboard_desc);
}
@Override
public Drawable getIcon() {
return ContextCompat.getDrawable(context, R.drawable.ic_action_keyboard);
}
@Override
public boolean hasSettings() {
return true;
}
@Override
public boolean hasMainActivity() {
return false;
}
@Override
public String[] getSupportedPackageTypes() {
return new String[]{PACKAGE_TYPE_MOUSEPAD_REQUEST};
}
@Override
public String[] getOutgoingPackageTypes() {
return new String[]{PACKAGE_TYPE_MOUSEPAD_ECHO, PACKAGE_TYPE_MOUSEPAD_KEYBOARDSTATE};
}
private boolean isValidSpecialKey(int key) {
return (specialKeyMap.get(key, 0) > 0);
}
private int getCharPos(ExtractedText extractedText, char ch, boolean forward) {
int pos = -1;
if (extractedText != null) {
if (!forward) // backward
pos = extractedText.text.toString().lastIndexOf(" ", extractedText.selectionEnd - 2);
else
pos = extractedText.text.toString().indexOf(" ", extractedText.selectionEnd + 1);
return pos;
}
return pos;
}
private int currentTextLength(ExtractedText extractedText) {
if (extractedText != null)
return extractedText.text.length();
return -1;
}
private int currentCursorPos(ExtractedText extractedText) {
if (extractedText != null)
return extractedText.selectionEnd;
return -1;
}
private Pair<Integer,Integer> currentSelection(ExtractedText extractedText) {
if (extractedText != null)
return new Pair<>(extractedText.selectionStart, extractedText.selectionEnd);
return new Pair<>(-1, -1);
}
private boolean handleSpecialKey(int key, boolean shift, boolean ctrl, boolean alt) {
int keyEvent = specialKeyMap.get(key, 0);
if (keyEvent == 0)
return false;
InputConnection inputConn = RemoteKeyboardService.instance.getCurrentInputConnection();
// Log.d("RemoteKeyboardPlugin", "Handling special key " + key + " translated to " + keyEvent + " shift=" + shift + " ctrl=" + ctrl + " alt=" + alt);
// special sequences:
if (ctrl && (keyEvent == KeyEvent.KEYCODE_DPAD_RIGHT)) {
// Ctrl + right -> next word
ExtractedText extractedText = inputConn.getExtractedText(new ExtractedTextRequest(), 0);
int pos = getCharPos(extractedText, ' ', keyEvent == KeyEvent.KEYCODE_DPAD_RIGHT);
if (pos == -1)
pos = currentTextLength(extractedText);
else
pos++;
int startPos = pos;
int endPos = pos;
if (shift) { // Shift -> select word (otherwise jump)
Pair<Integer,Integer> sel = currentSelection(extractedText);
int cursor = currentCursorPos(extractedText);
// Log.d("RemoteKeyboardPlugin", "Selection (to right): " + sel.first + " / " + sel.second + " cursor: " + cursor);
startPos = cursor;
if (sel.first < cursor || // active selection from left to right -> grow
sel.first > sel.second) // active selection from right to left -> shrink
startPos = sel.first;
}
inputConn.setSelection(startPos, endPos);
} else if (ctrl && keyEvent == KeyEvent.KEYCODE_DPAD_LEFT) {
// Ctrl + left -> previous word
ExtractedText extractedText = inputConn.getExtractedText(new ExtractedTextRequest(), 0);
int pos = getCharPos(extractedText, ' ', keyEvent == KeyEvent.KEYCODE_DPAD_RIGHT);
if (pos == -1)
pos = 0;
else
pos++;
int startPos = pos;
int endPos = pos;
if (shift) {
Pair<Integer,Integer> sel = currentSelection(extractedText);
int cursor = currentCursorPos(extractedText);
// Log.d("RemoteKeyboardPlugin", "Selection (to left): " + sel.first + " / " + sel.second + " cursor: " + cursor);
startPos = cursor;
if (cursor < sel.first || // active selection from right to left -> grow
sel.first < sel.second) // active selection from right to left -> shrink
startPos = sel.first;
}
inputConn.setSelection(startPos, endPos);
} else if (shift
&& (keyEvent == KeyEvent.KEYCODE_DPAD_LEFT
|| keyEvent == KeyEvent.KEYCODE_DPAD_RIGHT
|| keyEvent == KeyEvent.KEYCODE_DPAD_UP
|| keyEvent == KeyEvent.KEYCODE_DPAD_DOWN
|| keyEvent == KeyEvent.KEYCODE_MOVE_HOME
|| keyEvent == KeyEvent.KEYCODE_MOVE_END)) {
// Shift + up/down/left/right/home/end
long now = SystemClock.uptimeMillis();
inputConn.sendKeyEvent(new KeyEvent(now, now, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_SHIFT_LEFT, 0, 0));
inputConn.sendKeyEvent(new KeyEvent(now, now, KeyEvent.ACTION_DOWN, keyEvent, 0, KeyEvent.META_SHIFT_LEFT_ON));
inputConn.sendKeyEvent(new KeyEvent(now, now, KeyEvent.ACTION_UP, keyEvent, 0, KeyEvent.META_SHIFT_LEFT_ON));
inputConn.sendKeyEvent(new KeyEvent(now, now, KeyEvent.ACTION_UP, KeyEvent.KEYCODE_SHIFT_LEFT, 0, 0));
} else if (keyEvent == KeyEvent.KEYCODE_NUMPAD_ENTER
|| keyEvent == KeyEvent.KEYCODE_ENTER) {
// Enter key
EditorInfo editorInfo = RemoteKeyboardService.instance.getCurrentInputEditorInfo();
// Log.d("RemoteKeyboardPlugin", "Enter: " + editorInfo.imeOptions);
if (editorInfo != null
&& (((editorInfo.imeOptions & EditorInfo.IME_FLAG_NO_ENTER_ACTION) == 0)
|| ctrl)) { // Ctrl+Return overrides IME_FLAG_NO_ENTER_ACTION (FIXME: make configurable?)
// check for special DONE/GO/etc actions first:
int[] actions = { EditorInfo.IME_ACTION_GO, EditorInfo.IME_ACTION_NEXT,
EditorInfo.IME_ACTION_SEND, EditorInfo.IME_ACTION_SEARCH,
EditorInfo.IME_ACTION_DONE}; // note: DONE should be last or we might hide the ime instead of "go"
for (int i = 0; i < actions.length; i++) {
if ((editorInfo.imeOptions & actions[i]) == actions[i]) {
// Log.d("RemoteKeyboardPlugin", "Enter-action: " + actions[i]);
inputConn.performEditorAction(actions[i]);
return true;
}
}
} else {
// else: fall back to regular Enter-event:
// Log.d("RemoteKeyboardPlugin", "Enter: normal keypress");
inputConn.sendKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, keyEvent));
inputConn.sendKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, keyEvent));
}
} else {
// default handling:
inputConn.sendKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, keyEvent));
inputConn.sendKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, keyEvent));
}
return true;
}
private boolean handleVisibleKey(String key, boolean shift, boolean ctrl, boolean alt) {
// Log.d("RemoteKeyboardPlugin", "Handling visible key " + key + " shift=" + shift + " ctrl=" + ctrl + " alt=" + alt + " " + key.equalsIgnoreCase("c") + " " + key.length());
if (key.isEmpty())
return false;
InputConnection inputConn = RemoteKeyboardService.instance.getCurrentInputConnection();
if (inputConn == null)
return false;
// ctrl+c/v/x
if (key.equalsIgnoreCase("c") && ctrl) {
return inputConn.performContextMenuAction(android.R.id.copy);
} else if (key.equalsIgnoreCase("v") && ctrl)
return inputConn.performContextMenuAction(android.R.id.paste);
else if (key.equalsIgnoreCase("x") && ctrl)
return inputConn.performContextMenuAction(android.R.id.cut);
else if (key.equalsIgnoreCase("a") && ctrl)
return inputConn.performContextMenuAction(android.R.id.selectAll);
// Log.d("RemoteKeyboardPlugin", "Committing visible key '" + key + "'");
inputConn.commitText(key, key.length());
return true;
}
private boolean handleEvent(NetworkPackage np) {
if (np.has("specialKey") && isValidSpecialKey(np.getInt("specialKey")))
return handleSpecialKey(np.getInt("specialKey"), np.getBoolean("shift"),
np.getBoolean("ctrl"), np.getBoolean("alt"));
// try visible key
return handleVisibleKey(np.getString("key"), np.getBoolean("shift"),
np.getBoolean("ctrl"), np.getBoolean("alt"));
}
@Override
public boolean onPackageReceived(NetworkPackage np) {
if (!np.getType().equals(PACKAGE_TYPE_MOUSEPAD_REQUEST)
|| (!np.has("key") && !np.has("specialKey"))) { // expect at least key OR specialKey
Log.e("RemoteKeyboardPlugin", "Invalid package for remotekeyboard plugin!");
return false;
}
if (RemoteKeyboardService.instance == null) {
Log.i("RemoteKeyboardPlugin", "Remote keyboard is not the currently selected input method, dropping key");
return false;
}
if (!RemoteKeyboardService.instance.visible &&
PreferenceManager.getDefaultSharedPreferences(context).getBoolean(context.getString(R.string.remotekeyboard_editing_only), true)) {
Log.i("RemoteKeyboardPlugin", "Remote keyboard is currently not visible, dropping key");
return false;
}
if (!handleEvent(np)) {
Log.i("RemoteKeyboardPlugin", "Could not handle event!");
return false;
}
if (np.getBoolean("sendAck")) {
NetworkPackage reply = new NetworkPackage(PACKAGE_TYPE_MOUSEPAD_ECHO);
reply.set("key", np.getString("key"));
if (np.has("specialKey"))
reply.set("specialKey", np.getInt("specialKey"));
if (np.has("shift"))
reply.set("shift", np.getBoolean("shift"));
if (np.has("ctrl"))
reply.set("ctrl", np.getBoolean("ctrl"));
if (np.has("alt"))
reply.set("alt", np.getBoolean("alt"));
reply.set("isAck", true);
device.sendPackage(reply);
}
return true;
}
public void notifyKeyboardState(boolean state) {
Log.d("RemoteKeyboardPlugin", "Keyboardstate changed to " + state);
NetworkPackage np = new NetworkPackage(PACKAGE_TYPE_MOUSEPAD_KEYBOARDSTATE);
np.set("state", state);
device.sendPackage(np);
}
}

View File

@@ -0,0 +1,233 @@
/*
* Copyright 2017 Holger Kaelberer <holger.k@elberer.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License or (at your option) version 3 or any later version
* accepted by the membership of KDE e.V. (or its successor approved
* by the membership of KDE e.V.), which shall act as a proxy
* defined in Section 14 of version 3 of the license.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.kde.kdeconnect.Plugins.RemoteKeyboardPlugin;
import android.content.Context;
import android.content.Intent;
import android.inputmethodservice.InputMethodService;
import android.inputmethodservice.Keyboard;
import android.inputmethodservice.KeyboardView;
import android.inputmethodservice.KeyboardView.OnKeyboardActionListener;
import android.os.Handler;
import android.util.Log;
import android.view.View;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
import android.widget.Toast;
import org.kde.kdeconnect.UserInterface.MaterialActivity;
import org.kde.kdeconnect.UserInterface.PluginSettingsActivity;
import org.kde.kdeconnect_tp.R;
import java.util.ArrayList;
import java.util.List;
public class RemoteKeyboardService
extends InputMethodService
implements OnKeyboardActionListener {
/**
* Reference to our instance
* null if this InputMethod is not currently selected.
*/
public static RemoteKeyboardService instance = null;
/**
* Whether input is currently accepted
* Implies visible == true
*/
public boolean active = false;
/**
* Whether this InputMethod is currently visible.
*/
public boolean visible = false;
KeyboardView inputView = null;
private final int StatusKeyIdx = 3;
private final int connectedIcon = R.drawable.ic_phonelink_white_36dp;
private final int disconnectedIcon = R.drawable.ic_phonelink_off_white_36dp;
Handler handler;
void updateInputView() {
if (inputView == null)
return;
Keyboard currentKeyboard = inputView.getKeyboard();
List<Keyboard.Key> keys = currentKeyboard.getKeys();
boolean connected = RemoteKeyboardPlugin.isConnected();
// Log.d("RemoteKeyboardService", "Updating keyboard connection icon, connected=" + connected);
keys.get(StatusKeyIdx).icon = getResources().getDrawable(connected ? connectedIcon : disconnectedIcon);
inputView.invalidateKey(StatusKeyIdx);
}
@Override
public void onCreate() {
super.onCreate();
active = false;
visible = false;
instance = this;
handler = new Handler();
Log.d("RemoteKeyboardService", "Remote keyboard initialized");
}
@Override
public void onDestroy() {
super.onDestroy();
instance = null;
Log.d("RemoteKeyboardService", "Destroyed");
}
@Override
public void onInitializeInterface() {
super.onInitializeInterface();
}
@Override
public View onCreateInputView() {
// Log.d("RemoteKeyboardService", "onCreateInputView connected=" + RemoteKeyboardPlugin.isConnected());
inputView = new KeyboardView(this, null);
inputView.setKeyboard(new Keyboard(this, R.xml.remotekeyboardplugin_keyboard));
inputView.setPreviewEnabled(false);
inputView.setOnKeyboardActionListener(this);
updateInputView();
return inputView;
}
@Override
public void onStartInputView(EditorInfo attribute, boolean restarting) {
// Log.d("RemoteKeyboardService", "onStartInputView");
super.onStartInputView(attribute, restarting);
visible = true;
ArrayList<RemoteKeyboardPlugin> instances = RemoteKeyboardPlugin.acquireInstances();
try {
for (RemoteKeyboardPlugin i: instances)
i.notifyKeyboardState(true);
} finally {
RemoteKeyboardPlugin.releaseInstances();
}
}
@Override
public void onFinishInputView(boolean finishingInput) {
// Log.d("RemoteKeyboardService", "onFinishInputView");
super.onFinishInputView(finishingInput);
visible = false;
ArrayList<RemoteKeyboardPlugin> instances = RemoteKeyboardPlugin.acquireInstances();
try {
for (RemoteKeyboardPlugin i: instances)
i.notifyKeyboardState(false);
} finally {
RemoteKeyboardPlugin.releaseInstances();
}
}
@Override
public void onStartInput(EditorInfo attribute, boolean restarting) {
// Log.d("RemoteKeyboardService", "onStartInput");
super.onStartInput(attribute, restarting);
active = true;
}
@Override
public void onFinishInput() {
// Log.d("RemoteKeyboardService", "onFinishInput");
super.onFinishInput();
active = false;
}
@Override
public void onPress(int primaryCode) {
switch (primaryCode) {
case 0: { // "hide keyboard"
requestHideSelf(0);
break;
}
case 1: { // "settings"
ArrayList<RemoteKeyboardPlugin> instances = RemoteKeyboardPlugin.acquireInstances();
try {
if (instances.size() == 1) { // single instance of RemoteKeyboardPlugin -> access its settings
RemoteKeyboardPlugin plugin = instances.get(0);
if (plugin != null) {
Intent intent = new Intent(this, PluginSettingsActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra("plugin_display_name", plugin.getDisplayName());
intent.putExtra("plugin_key", plugin.getPluginKey());
startActivity(intent);
}
} else { // != 1 instance of plugin -> show main activity view
Intent intent = new Intent(this, MaterialActivity.class);
intent.putExtra("forceOverview", true);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
if (instances.size() < 1)
Toast.makeText(this, R.string.remotekeyboard_not_connected, Toast.LENGTH_SHORT).show();
else // instances.size() > 1
Toast.makeText(this, R.string.remotekeyboard_multiple_connections, Toast.LENGTH_SHORT).show();
}
} finally {
RemoteKeyboardPlugin.releaseInstances();
}
break;
}
case 2: { // "keyboard"
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
imm.showInputMethodPicker();
break;
}
case 3: { // "connected"?
if (RemoteKeyboardPlugin.isConnected())
Toast.makeText(this, R.string.remotekeyboard_connected, Toast.LENGTH_SHORT).show();
else
Toast.makeText(this, R.string.remotekeyboard_not_connected, Toast.LENGTH_SHORT).show();
break;
}
}
}
@Override
public void onKey(int primaryCode, int[] keyCodes) {
}
@Override
public void onText(CharSequence text) {
}
@Override
public void swipeRight() {
}
@Override
public void swipeLeft() {
}
@Override
public void swipeDown() {
}
@Override
public void swipeUp() {
}
@Override
public void onRelease(int primaryCode) {
}
}

View File

@@ -0,0 +1,3 @@
Besides the official Android examples about implementing IMEs I learned a lot about using
the Android APIs around InputConnection from the excellent "Remote Keyboard" app from onyxbits
(http://www.onyxbits.de/remotekeyboard). Thanks!

View File

@@ -0,0 +1,40 @@
/*
* Copyright 2016 Thomas Posch <kdeconnect@online.posch.name>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License or (at your option) version 3 or any later version
* accepted by the membership of KDE e.V. (or its successor approved
* by the membership of KDE e.V.), which shall act as a proxy
* defined in Section 14 of version 3 of the license.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.kde.kdeconnect.Plugins.RunCommandPlugin;
import org.kde.kdeconnect.UserInterface.List.EntryItem;
public class CommandEntry extends EntryItem {
private final String key;
public CommandEntry(String name, String cmd, String key) {
super(name, cmd);
this.key = key;
}
public String getKey() {
return key;
}
public String getName() {
return title;
}
}

View File

@@ -32,11 +32,12 @@ import org.json.JSONException;
import org.json.JSONObject;
import org.kde.kdeconnect.BackgroundService;
import org.kde.kdeconnect.Device;
import org.kde.kdeconnect.UserInterface.List.EntryItem;
import org.kde.kdeconnect.UserInterface.List.ListAdapter;
import org.kde.kdeconnect_tp.R;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
public class RunCommandActivity extends ActionBarActivity {
@@ -59,28 +60,33 @@ public class RunCommandActivity extends ActionBarActivity {
public void run() {
ListView view = (ListView) findViewById(R.id.listView1);
final ArrayList<JSONObject> commands = plugin.getCommandList();
ArrayList<ListAdapter.Item> commandItems = new ArrayList<>();
for (JSONObject obj : commands) {
final ArrayList<ListAdapter.Item> commandItems = new ArrayList<>();
for (JSONObject obj : plugin.getCommandList()) {
try {
commandItems.add(new EntryItem(obj.getString("name"), obj.getString("command")));
commandItems.add(new CommandEntry(obj.getString("name"),
obj.getString("command"), obj.getString("key")));
} catch (JSONException e) {
e.printStackTrace();
}
}
Collections.sort(commandItems, new Comparator<ListAdapter.Item>() {
@Override
public int compare(ListAdapter.Item lhs, ListAdapter.Item rhs) {
String lName = ((CommandEntry) lhs).getName();
String rName = ((CommandEntry) rhs).getName();
return lName.compareTo(rName);
}
});
ListAdapter adapter = new ListAdapter(RunCommandActivity.this, commandItems);
view.setAdapter(adapter);
view.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
try {
plugin.runCommand(commands.get(i).getString("key"));
} catch (JSONException e) {
e.printStackTrace();
}
CommandEntry entry = (CommandEntry) commandItems.get(i);
plugin.runCommand(entry.getKey());
}
});
}

View File

@@ -68,57 +68,55 @@ public class SftpPlugin extends Plugin {
NetworkPackage np2 = new NetworkPackage(PACKAGE_TYPE_SFTP);
np2.set("ip", server.getLocalIpAddress());
np2.set("port", server.port);
np2.set("user", server.passwordAuth.getUser());
np2.set("password", server.passwordAuth.getPassword());
np2.set("port", server.getPort());
np2.set("user", SimpleSftpServer.USER);
np2.set("password", server.getPassword());
//Kept for compatibility, in case "multiPaths" is not possible or the other end does not support it
np2.set("path", Environment.getExternalStorageDirectory().getAbsolutePath());
File root = new File("/");
if (root.canExecute() && root.canRead()) {
List<StorageHelper.StorageInfo> storageList = StorageHelper.getStorageList();
ArrayList<String> paths = new ArrayList<>();
ArrayList<String> pathNames = new ArrayList<>();
List<StorageHelper.StorageInfo> storageList = StorageHelper.getStorageList();
ArrayList<String> paths = new ArrayList<>();
ArrayList<String> pathNames = new ArrayList<>();
for (StorageHelper.StorageInfo storage : storageList) {
paths.add(storage.path);
StringBuilder res = new StringBuilder();
for (StorageHelper.StorageInfo storage : storageList) {
paths.add(storage.path);
StringBuilder res = new StringBuilder();
if (storageList.size() > 1) {
if (!storage.removable) {
res.append(context.getString(R.string.sftp_internal_storage));
} else if (storage.number > 1) {
res.append(context.getString(R.string.sftp_sdcard_num, storage.number));
} else {
res.append(context.getString(R.string.sftp_sdcard));
}
if (storageList.size() > 1) {
if (!storage.removable) {
res.append(context.getString(R.string.sftp_internal_storage));
} else if (storage.number > 1) {
res.append(context.getString(R.string.sftp_sdcard_num, storage.number));
} else {
res.append(context.getString(R.string.sftp_all_files));
res.append(context.getString(R.string.sftp_sdcard));
}
String pathName = res.toString();
if (storage.readonly) {
res.append(" ");
res.append(context.getString(R.string.sftp_readonly));
}
pathNames.add(res.toString());
} else {
res.append(context.getString(R.string.sftp_all_files));
}
String pathName = res.toString();
if (storage.readonly) {
res.append(" ");
res.append(context.getString(R.string.sftp_readonly));
}
pathNames.add(res.toString());
//Shortcut for users that only want to browse camera pictures
String dcim = storage.path + "/DCIM/Camera";
if (new File(dcim).exists()) {
paths.add(dcim);
if (storageList.size() > 1) {
pathNames.add(context.getString(R.string.sftp_camera) + "(" + pathName + ")");
} else {
pathNames.add(context.getString(R.string.sftp_camera));
}
//Shortcut for users that only want to browse camera pictures
String dcim = storage.path + "/DCIM/Camera";
if (new File(dcim).exists()) {
paths.add(dcim);
if (storageList.size() > 1) {
pathNames.add(context.getString(R.string.sftp_camera) + "(" + pathName + ")");
} else {
pathNames.add(context.getString(R.string.sftp_camera));
}
}
}
if (paths.size() > 0) {
np2.set("multiPaths", paths);
np2.set("pathNames", pathNames);
if (paths.size() > 0) {
np2.set("multiPaths", paths);
np2.set("pathNames", pathNames);
}
}
device.sendPackage(np2);

View File

@@ -21,6 +21,7 @@
package org.kde.kdeconnect.Plugins.SftpPlugin;
import android.content.Context;
import android.net.Uri;
import android.util.Log;
import org.apache.sshd.SshServer;
@@ -42,33 +43,33 @@ import org.apache.sshd.server.keyprovider.SimpleGeneratorHostKeyProvider;
import org.apache.sshd.server.session.ServerSession;
import org.apache.sshd.server.sftp.SftpSubsystem;
import org.kde.kdeconnect.Device;
import org.kde.kdeconnect.Helpers.MediaStoreHelper;
import org.kde.kdeconnect.Helpers.RandomHelper;
import org.kde.kdeconnect.Helpers.SecurityHelpers.SslHelper;
import java.io.File;
import java.io.IOException;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.security.PublicKey;
import java.security.Security;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
class SimpleSftpServer {
private static final int STARTPORT = 1739;
private static final int ENDPORT = 1764;
private static final String USER = "kdeconnect";
static final String USER = "kdeconnect";
public static int port = -1;
private static boolean started = false;
private int port = -1;
private boolean started = false;
public final SimplePasswordAuthenticator passwordAuth = new SimplePasswordAuthenticator();
public final SimplePublicKeyAuthenticator keyAuth = new SimplePublicKeyAuthenticator();
private final SimplePasswordAuthenticator passwordAuth = new SimplePasswordAuthenticator();
private final SimplePublicKeyAuthenticator keyAuth = new SimplePublicKeyAuthenticator();
static {
Security.insertProviderAt(SslHelper.BC, 1);
@@ -76,20 +77,20 @@ class SimpleSftpServer {
}
private final SshServer sshd = SshServer.setUpDefaultServer();
public void init(Context ctx, Device device) {
public void init(Context context, Device device) {
sshd.setKeyExchangeFactories(Arrays.asList(
new DHG14.Factory(),
new DHG1.Factory()));
passwordAuth.setUser(USER);
sshd.setKeyPairProvider(new SimpleGeneratorHostKeyProvider(ctx.getFilesDir() + "/sftpd.ser"));
sshd.setKeyPairProvider(new SimpleGeneratorHostKeyProvider(context.getFilesDir() + "/sftpd.ser"));
sshd.setFileSystemFactory(new SecureFileSystemFactory());
sshd.setFileSystemFactory(new AndroidFileSystemFactory(context));
sshd.setCommandFactory(new ScpCommandFactory());
sshd.setSubsystemFactories(Collections.singletonList((NamedFactory<Command>)new SftpSubsystem.Factory()));
if (device.publicKey != null) {
keyAuth.addKey(device.publicKey);
keyAuth.deviceKey = device.publicKey;
sshd.setPublickeyAuthenticator(keyAuth);
}
sshd.setPasswordAuthenticator(passwordAuth);
@@ -98,8 +99,7 @@ class SimpleSftpServer {
public boolean start() {
if (!started) {
String password = RandomHelper.randomString(28);
passwordAuth.setPassword(password);
passwordAuth.password = RandomHelper.randomString(28);
port = STARTPORT;
while(!started) {
@@ -131,11 +131,30 @@ class SimpleSftpServer {
}
}
public String getPassword() {
return passwordAuth.password;
}
public int getPort() {
return port;
}
public String getLocalIpAddress() {
String ip6 = null;
try {
for (Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces(); en.hasMoreElements();) {
NetworkInterface intf = en.nextElement();
// Anything with rmnet is related to cellular connections or USB
// tethering mechanisms. See:
//
// https://android.googlesource.com/kernel/msm/+/android-msm-flo-3.4-kitkat-mr1/Documentation/usb/gadget_rmnet.txt
//
// If we run across an interface that has this, we can safely
// ignore it. In fact, it's much safer to do. If we don't, we
// might get invalid IP adddresses out of it.
if(intf.getDisplayName().contains("rmnet")) continue;
for (Enumeration<InetAddress> enumIpAddr = intf.getInetAddresses(); enumIpAddr.hasMoreElements();) {
InetAddress inetAddress = enumIpAddr.nextElement();
if (!inetAddress.isLoopbackAddress()) {
@@ -153,92 +172,89 @@ class SimpleSftpServer {
return ip6;
}
static class SecureFileSystemFactory implements FileSystemFactory {
static class AndroidFileSystemFactory implements FileSystemFactory {
public SecureFileSystemFactory() {}
final private Context context;
public AndroidFileSystemFactory(Context context) {
this.context = context;
}
@Override
public FileSystemView createFileSystemView(final Session username) {
final String base = "/";
return new SecureFileSystemView(base, username.getUsername());
return new AndroidFileSystemView(username.getUsername(), context);
}
}
static class SecureFileSystemView extends NativeFileSystemView {
// the first and the last character will always be '/'
// It is always with respect to the root directory.
private String currDir = "/";
private String rootDir = "/";
private String userName;
//
public SecureFileSystemView(final String rootDir, final String userName) {
super(userName);
this.rootDir = NativeSshFile.normalizeSeparateChar(rootDir);
static class AndroidFileSystemView extends NativeFileSystemView {
final private String userName;
final private Context context;
public AndroidFileSystemView(final String userName, Context context) {
super(userName, true);
this.userName = userName;
}
//
@Override
public SshFile getFile(final String file) {
return getFile(currDir, file);
this.context = context;
}
@Override
public SshFile getFile(final SshFile baseDir, final String file) {
return getFile(baseDir.getAbsolutePath(), file);
}
//
protected SshFile getFile(final String dir, final String file) {
// get actual file object
final boolean caseInsensitive = false;
String physicalName = NativeSshFile.getPhysicalName("/", dir, file, caseInsensitive);
File fileObj = new File(rootDir, physicalName); // chroot
// strip the root directory and return
String userFileName = physicalName.substring("/".length() - 1);
return new SecureSshFile(userFileName, fileObj, userName);
File fileObj = new File(dir, file);
return new AndroidSshFile(fileObj, userName, context);
}
}
static class SecureSshFile extends NativeSshFile {
public SecureSshFile(final String fileName, final File file, final String userName) {
super(fileName, file, userName);
static class AndroidSshFile extends NativeSshFile {
final private Context context;
final private File file;
public AndroidSshFile(final File file, final String userName, Context context) {
super(file.getAbsolutePath(), file, userName);
this.context = context;
this.file = file;
}
@Override
public boolean delete() {
//Log.e("Sshd", "deleting file");
boolean ret = super.delete();
if (ret) {
MediaStoreHelper.indexFile(context, Uri.fromFile(file));
}
return ret;
}
@Override
public boolean create() throws IOException {
//Log.e("Sshd", "creating file");
boolean ret = super.create();
if (ret) {
MediaStoreHelper.indexFile(context, Uri.fromFile(file));
}
return ret;
}
}
static class SimplePasswordAuthenticator implements PasswordAuthenticator {
public void setUser(String user) {this.user = user;}
public String getUser() {return this.user;}
public void setPassword(String password) {this.password = password;}
public String getPassword() {return this.password;}
public String password;
@Override
public boolean authenticate(String user, String password, ServerSession session) {
return user.equals(this.user) && password.equals(this.password);
return user.equals(SimpleSftpServer.USER) && password.equals(this.password);
}
private String user;
private String password;
}
static class SimplePublicKeyAuthenticator implements PublickeyAuthenticator {
private final List<PublicKey> keys = new ArrayList<>();
public void addKey(PublicKey key) {
keys.add(key);
}
public PublicKey deviceKey;
@Override
public boolean authenticate(String user, PublicKey key, ServerSession session) {
for (PublicKey k : keys) {
if (key.equals(k)) {
return true;
}
}
return false;
return deviceKey.equals(key);
}
}

View File

@@ -0,0 +1,122 @@
package org.kde.kdeconnect.Plugins.SharePlugin;
import android.app.NotificationManager;
import android.content.Context;
import android.content.res.Resources;
import android.support.v4.app.NotificationCompat;
import org.kde.kdeconnect.Device;
import org.kde.kdeconnect.Helpers.NotificationHelper;
import org.kde.kdeconnect.NetworkPackage;
import org.kde.kdeconnect_tp.R;
import java.util.ArrayList;
class NotificationUpdateCallback extends Device.SendPackageStatusCallback {
final Context context;
final Resources res;
final Device device;
final NotificationManager notificationManager;
final NotificationCompat.Builder builder;
final ArrayList<NetworkPackage> toSend;
final int notificationId;
int sentFiles = 0;
final int numFiles;
NotificationUpdateCallback(Context context, Device device, ArrayList<NetworkPackage> toSend) {
this.context = context;
this.toSend = toSend;
this.device = device;
this.res = context.getResources();
String title;
if (toSend.size() > 1) {
title = res.getString(R.string.outgoing_files_title, device.getName());
} else {
title = res.getString(R.string.outgoing_file_title, device.getName());
}
notificationManager = (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE);
builder = new NotificationCompat.Builder(context)
.setSmallIcon(android.R.drawable.stat_sys_upload)
.setAutoCancel(true)
.setProgress(100, 0, false)
.setContentTitle(title)
.setTicker(title);
notificationId = (int)System.currentTimeMillis();
numFiles = toSend.size();
}
@Override
public void onProgressChanged(int progress) {
builder.setProgress(100 * numFiles, (100 * sentFiles) + progress, false);
NotificationHelper.notifyCompat(notificationManager, notificationId, builder.build());
}
@Override
public void onSuccess() {
sentFiles++;
if (sentFiles == numFiles) {
updateDone(true);
} else {
updateText();
}
NotificationHelper.notifyCompat(notificationManager, notificationId, builder.build());
}
@Override
public void onFailure(Throwable e) {
updateDone(false);
NotificationHelper.notifyCompat(notificationManager, notificationId, builder.build());
}
private void updateText() {
String text;
if (numFiles > 1) {
text = res.getString(R.string.outgoing_files_text, sentFiles, numFiles);
} else {
text = res.getString(R.string.outgoing_file_text, device.getName());
}
builder.setContentText(text);
}
private void updateDone(boolean successful) {
int icon;
String title;
String text;
int progress;
if (successful) {
progress = 1;
if (numFiles > 1) {
text = res.getString(R.string.outgoing_files_text, sentFiles, numFiles);
} else {
final String filename = toSend.get(0).getString("filename");
text = res.getString(R.string.sent_file_text, filename);
}
title = res.getString(R.string.sent_file_title, device.getName());
icon = android.R.drawable.stat_sys_upload_done;
} else {
progress = 0;
final String filename = toSend.get(sentFiles).getString("filename");
title = res.getString(R.string.sent_file_failed_title, device.getName());
text = res.getString(R.string.sent_file_failed_text, filename);
icon = android.R.drawable.stat_notify_error;
}
builder.setOngoing(false)
.setTicker(title)
.setContentTitle(title)
.setContentText(text)
.setSmallIcon(icon)
.setProgress(progress, progress, false); //setting progress to 0 out of 0 remove the progress bar
}
}

View File

@@ -21,8 +21,10 @@
package org.kde.kdeconnect.Plugins.SharePlugin;
import android.app.Activity;
import android.content.ClipData;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.util.Log;
@@ -47,6 +49,9 @@ public class SendFileActivity extends ActionBarActivity {
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("*/*");
if ((Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2)) {
intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
}
intent.addCategory(Intent.CATEGORY_OPENABLE);
try {
startActivityForResult(
@@ -62,23 +67,39 @@ public class SendFileActivity extends ActionBarActivity {
switch (requestCode) {
case Activity.RESULT_FIRST_USER:
if (resultCode == RESULT_OK) {
final Uri uri = data.getData();
Log.e("SendFileActivity", "File Uri: " + uri.toString());
BackgroundService.RunCommand(this, new BackgroundService.InstanceCallback() {
@Override
public void onServiceStart(BackgroundService service) {
Device device = service.getDevice(mDeviceId);
if (device == null) {
Log.e("SendFileActivity", "Device is null");
finish();
return;
}
ArrayList<Uri> uris = new ArrayList<>();
uris.add(uri);
SharePlugin.queuedSendUriList(getApplicationContext(), device, uris);
final ArrayList<Uri> uris = new ArrayList<>();
Uri uri = data.getData();
if (uri != null) {
uris.add(uri);
}
if ((Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2)) {
ClipData clipdata = data.getClipData();
if (clipdata != null) {
for (int i = 0; i < clipdata.getItemCount(); i++) {
uris.add(clipdata.getItemAt(i).getUri());
}
}
});
}
if (uris.isEmpty()) {
Log.w("SendFileActivity", "No files to send?");
} else {
BackgroundService.RunCommand(this, new BackgroundService.InstanceCallback() {
@Override
public void onServiceStart(BackgroundService service) {
Device device = service.getDevice(mDeviceId);
if (device == null) {
Log.e("SendFileActivity", "Device is null");
finish();
return;
}
SharePlugin.queuedSendUriList(getApplicationContext(), device, uris);
}
});
}
}
finish();
break;

View File

@@ -198,6 +198,7 @@ public class ShareActivity extends ActionBarActivity {
ActionBar actionBar = getSupportActionBar();
actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_HOME | ActionBar.DISPLAY_SHOW_TITLE | ActionBar.DISPLAY_SHOW_CUSTOM);
setContentView(R.layout.activity_list);
}

View File

@@ -21,6 +21,7 @@
package org.kde.kdeconnect.Plugins.SharePlugin;
import android.app.Activity;
import android.app.DownloadManager;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
@@ -33,25 +34,26 @@ import android.content.res.Resources;
import android.database.Cursor;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Environment;
import android.os.Handler;
import android.os.Looper;
import android.os.Build;
import android.preference.PreferenceManager;
import android.provider.MediaStore;
import android.support.v4.app.NotificationCompat;
import android.support.v4.app.TaskStackBuilder;
import android.support.v4.content.ContextCompat;
import android.support.v4.provider.DocumentFile;
import android.util.Log;
import android.widget.Toast;
import org.kde.kdeconnect.Device;
import org.kde.kdeconnect.Helpers.FilesHelper;
import org.kde.kdeconnect.Helpers.MediaStoreHelper;
import org.kde.kdeconnect.Helpers.NotificationHelper;
import org.kde.kdeconnect.NetworkPackage;
import org.kde.kdeconnect.Plugins.Plugin;
import org.kde.kdeconnect.UserInterface.SettingsActivity;
import org.kde.kdeconnect_tp.R;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
@@ -110,23 +112,25 @@ public class SharePlugin extends Plugin {
final InputStream input = np.getPayload();
final long fileLength = np.getPayloadSize();
final String filename = np.getString("filename", Long.toString(System.currentTimeMillis()));
final String originalFilename = np.getString("filename", Long.toString(System.currentTimeMillis()));
String deviceDir = FilesHelper.toFileSystemSafeName(device.getName());
//Get the external storage and append "/kdeconnect/DEVICE_NAME/"
String destinationDir = Environment.getExternalStorageDirectory().getPath();
destinationDir = new File(destinationDir, "kdeconnect").getPath();
destinationDir = new File(destinationDir, deviceDir).getPath();
//We need to check for already existing files only when storing in the default path.
//User-defined paths use the new Storage Access Framework that already handles this.
final boolean customDestination = ShareSettingsActivity.isCustomDestinationEnabled(context);
final String defaultPath = ShareSettingsActivity.getDefaultDestinationDirectory().getAbsolutePath();
final String filename = customDestination? originalFilename : FilesHelper.findNonExistingNameForNewFile(defaultPath, originalFilename);
//Create directories if needed
new File(destinationDir).mkdirs();
String displayName = FilesHelper.getFileNameWithoutExt(filename);
final String mimeType = FilesHelper.getMimeTypeFromFile(filename);
//Append filename to the destination path
final File destinationFullPath = new File(destinationDir, filename);
if ("*/*".equals(mimeType)) {
displayName = filename;
}
//Log.e("SharePlugin", "destinationFullPath:" + destinationFullPath);
final NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
final DocumentFile destinationFolderDocument = ShareSettingsActivity.getDestinationDirectory(context);
final DocumentFile destinationDocument = destinationFolderDocument.createFile(mimeType, displayName);
final OutputStream destinationOutput = context.getContentResolver().openOutputStream(destinationDocument.getUri());
final Uri destinationUri = destinationDocument.getUri();
final int notificationId = (int)System.currentTimeMillis();
Resources res = context.getResources();
@@ -139,103 +143,84 @@ public class SharePlugin extends Plugin {
.setOngoing(true)
.setProgress(100,0,true);
try {
notificationManager.notify(notificationId,builder.build());
} catch(Exception e) {
//4.1 will throw an exception about not having the VIBRATE permission, ignore it.
//https://android.googlesource.com/platform/frameworks/base/+/android-4.2.1_r1.2%5E%5E!/
}
final NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
NotificationHelper.notifyCompat(notificationManager,notificationId, builder.build());
new Thread(new Runnable() {
@Override
public void run() {
OutputStream output = null;
boolean successul = true;
boolean successful = true;
try {
output = new FileOutputStream(destinationFullPath.getPath());
byte data[] = new byte[1024];
long progress = 0, prevProgressPercentage = 0;
int count;
while ((count = input.read(data)) >= 0) {
progress += count;
output.write(data, 0, count);
destinationOutput.write(data, 0, count);
if (fileLength > 0) {
if (progress >= fileLength) break;
long progressPercentage = (progress * 100 / fileLength);
if (progressPercentage != prevProgressPercentage) {
prevProgressPercentage = progressPercentage;
builder.setProgress(100, (int) progressPercentage, false);
try {
notificationManager.notify(notificationId,builder.build());
} catch(Exception e) {
//4.1 will throw an exception about not having the VIBRATE permission, ignore it.
//https://android.googlesource.com/platform/frameworks/base/+/android-4.2.1_r1.2%5E%5E!/
}
NotificationHelper.notifyCompat(notificationManager, notificationId, builder.build());
}
}
//else Log.e("SharePlugin", "Infinite loop? :D");
}
output.flush();
destinationOutput.flush();
} catch (Exception e) {
successul = false;
successful = false;
Log.e("SharePlugin", "Receiver thread exception");
e.printStackTrace();
} finally {
try { output.close(); } catch (Exception e) {}
try { destinationOutput.close(); } catch (Exception e) {}
try { input.close(); } catch (Exception e) {}
}
try {
Log.i("SharePlugin", "Transfer finished");
//Make sure it is added to the Android Gallery
Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
mediaScanIntent.setData(Uri.fromFile(destinationFullPath));
context.sendBroadcast(mediaScanIntent);
Log.i("SharePlugin", "Transfer finished: "+destinationUri.getPath());
//Update the notification and allow to open the file from it
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.fromFile(destinationFullPath), FilesHelper.getMimeTypeFromFile(destinationFullPath.getPath()));
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
TaskStackBuilder stackBuilder = TaskStackBuilder.create(context);
stackBuilder.addNextIntent(intent);
PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(
0,
PendingIntent.FLAG_UPDATE_CURRENT
);
Resources res = context.getResources();
String message = successul? res.getString(R.string.received_file_title, device.getName()) : res.getString(R.string.received_file_fail_title, device.getName());
String message = successful? res.getString(R.string.received_file_title, device.getName()) : res.getString(R.string.received_file_fail_title, device.getName());
NotificationCompat.Builder builder = new NotificationCompat.Builder(context)
.setContentTitle(message)
.setTicker(message)
.setSmallIcon(android.R.drawable.stat_sys_download_done)
.setAutoCancel(true);
if (successul) {
builder.setContentText(res.getString(R.string.received_file_text, filename))
if (successful) {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(destinationUri, mimeType);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
TaskStackBuilder stackBuilder = TaskStackBuilder.create(context);
stackBuilder.addNextIntent(intent);
PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
builder.setContentText(res.getString(R.string.received_file_text, destinationDocument.getName()))
.setContentIntent(resultPendingIntent);
}
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
if (prefs.getBoolean("share_notification_preference", true)) {
builder.setDefaults(Notification.DEFAULT_ALL);
}
NotificationHelper.notifyCompat(notificationManager, notificationId, builder.build());
try {
notificationManager.notify(notificationId,builder.build());
} catch(Exception e) {
//4.1 will throw an exception about not having the VIBRATE permission, ignore it.
//https://android.googlesource.com/platform/frameworks/base/+/android-4.2.1_r1.2%5E%5E!/
if (successful) {
if (!customDestination && Build.VERSION.SDK_INT >= 12) {
Log.i("SharePlugin","Adding to downloads");
DownloadManager manager = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE);
manager.addCompletedDownload(destinationUri.getLastPathSegment(), device.getName(), true, mimeType, destinationUri.getPath(), fileLength, false);
} else {
//Make sure it is added to the Android Gallery anyway
MediaStoreHelper.indexFile(context, destinationUri);
}
}
} catch (Exception e) {
Log.e("SharePlugin", "Receiver thread exception");
e.printStackTrace();
}
}
}).start();
@@ -244,7 +229,7 @@ public class SharePlugin extends Plugin {
Log.i("SharePlugin", "hasText");
String text = np.getString("text");
if(android.os.Build.VERSION.SDK_INT >= 11) {
if(Build.VERSION.SDK_INT >= 11) {
ClipboardManager cm = (ClipboardManager)context.getSystemService(Context.CLIPBOARD_SERVICE);
cm.setText(text);
} else {
@@ -283,12 +268,7 @@ public class SharePlugin extends Plugin {
.build();
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
try {
notificationManager.notify((int) System.currentTimeMillis(), noti);
} catch (Exception e) {
//4.1 will throw an exception about not having the VIBRATE permission, ignore it.
//https://android.googlesource.com/platform/frameworks/base/+/android-4.2.1_r1.2%5E%5E!/
}
NotificationHelper.notifyCompat(notificationManager, (int) System.currentTimeMillis(), noti);
}
} else {
Log.e("SharePlugin", "Error: Nothing attached!");
@@ -303,37 +283,57 @@ public class SharePlugin extends Plugin {
return true;
}
@Override
public void startPreferencesActivity(SettingsActivity parentActivity) {
Intent intent = new Intent(parentActivity, ShareSettingsActivity.class);
intent.putExtra("plugin_display_name", getDisplayName());
intent.putExtra("plugin_key", getPluginKey());
parentActivity.startActivity(intent);
}
static void queuedSendUriList(Context context, final Device device, final ArrayList<Uri> uriList) {
//Read all the data early, as we only have permissions to do it while the activity is alive
final ArrayList<NetworkPackage> toSend = new ArrayList<>();
for (Uri uri : uriList) {
toSend.add(uriToNetworkPackage(context, uri));
}
//Callback that shows a progress notification
final NotificationUpdateCallback notificationUpdateCallback = new NotificationUpdateCallback(context, device, toSend);
//Do the sending in background
new Thread(new Runnable() {
@Override
public void run() {
//Actually send the files
try {
for (NetworkPackage np : toSend) {
boolean success = device.sendPackageBlocking(np, notificationUpdateCallback);
if (!success) {
Log.e("SharePlugin","Error sending files");
return;
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
}
//Create the network package from the URI
private static NetworkPackage uriToNetworkPackage(final Context context, final Uri uri) {
static void queuedSendUriList(final Context context, final Device device, final ArrayList<Uri> uriList) {
try {
Uri uri = uriList.remove(0);
ContentResolver cr = context.getContentResolver();
InputStream inputStream = cr.openInputStream(uri);
NetworkPackage np = new NetworkPackage(PACKAGE_TYPE_SHARE_REQUEST);
long size = -1;
final NotificationManager notificationManager = (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE);
final int notificationId = (int)System.currentTimeMillis();
final NotificationCompat.Builder builder ;
Resources res = context.getResources();
builder = new NotificationCompat.Builder(context)
.setContentTitle(res.getString(R.string.outgoing_file_title, device.getName()))
.setTicker(res.getString(R.string.outgoing_file_title, device.getName()))
.setSmallIcon(android.R.drawable.stat_sys_upload)
.setAutoCancel(true)
.setOngoing(true)
.setProgress(100,0,true);
try {
notificationManager.notify(notificationId,builder.build());
} catch(Exception e) {
//4.1 will throw an exception about not having the VIBRATE permission, ignore it.
//https://android.googlesource.com/platform/frameworks/base/+/android-4.2.1_r1.2%5E%5E!/
}
final Handler progressBarHandler = new Handler(Looper.getMainLooper());
if (uri.getScheme().equals("file")) {
// file:// is a non media uri, so we cannot query the ContentProvider
@@ -360,7 +360,7 @@ public class SharePlugin extends Plugin {
size = new File(path).length();
} catch(Exception unused) {
Log.e("SendFileActivity", "Could not resolve media to a file, trying to get info as media");
Log.w("SendFileActivity", "Could not resolve media to a file, trying to get info as media");
try {
int column_index = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DISPLAY_NAME);
@@ -389,108 +389,15 @@ public class SharePlugin extends Plugin {
np.setPayload(inputStream, size);
final String filename = np.getString("filename");
builder.setContentText(res.getString(R.string.outgoing_file_text,filename));
try {
notificationManager.notify(notificationId,builder.build());
} catch(Exception e) {
//4.1 will throw an exception about not having the VIBRATE permission, ignore it.
//https://android.googlesource.com/platform/frameworks/base/+/android-4.2.1_r1.2%5E%5E!/
}
device.sendPackage(np, new Device.SendPackageStatusCallback() {
int prevProgress = 0;
@Override
public void onProgressChanged(final int progress) {
if (progress != prevProgress) {
prevProgress = progress;
progressBarHandler.post(new Runnable() {
@Override
public void run() {
builder.setProgress(100, progress, false);
try {
notificationManager.notify(notificationId,builder.build());
} catch(Exception e) {
//4.1 will throw an exception about not having the VIBRATE permission, ignore it.
//https://android.googlesource.com/platform/frameworks/base/+/android-4.2.1_r1.2%5E%5E!/
}
}
});
}
}
@Override
public void onSuccess() {
progressBarHandler.post(new Runnable() {
@Override
public void run() {
Resources res = context.getResources();
NotificationCompat.Builder anotherBuilder = new NotificationCompat.Builder(context)
.setContentTitle(res.getString(R.string.sent_file_title, device.getName()))
.setContentText(res.getString(R.string.sent_file_text, filename))
.setTicker(res.getString(R.string.sent_file_title, device.getName()))
.setSmallIcon(android.R.drawable.stat_sys_upload_done)
.setOngoing(false)
.setAutoCancel(true);
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
if (prefs.getBoolean("share_notification_preference", true)) {
anotherBuilder.setDefaults(Notification.DEFAULT_ALL);
}
try {
notificationManager.notify(notificationId,anotherBuilder.build());
} catch(Exception e) {
//4.1 will throw an exception about not having the VIBRATE permission, ignore it.
//https://android.googlesource.com/platform/frameworks/base/+/android-4.2.1_r1.2%5E%5E!/
}
}
});
if (!uriList.isEmpty()) queuedSendUriList(context, device, uriList);
else Log.i("SendFileActivity", "All files sent");
}
@Override
public void onFailure(Throwable e) {
progressBarHandler.post(new Runnable() {
@Override
public void run() {
Resources res = context.getResources();
NotificationCompat.Builder anotherBuilder = new NotificationCompat.Builder(context)
.setContentTitle(res.getString(R.string.sent_file_failed_title, device.getName()))
.setContentText(res.getString(R.string.sent_file_failed_text, filename))
.setTicker(res.getString(R.string.sent_file_title, device.getName()))
.setSmallIcon(android.R.drawable.stat_notify_error)
.setOngoing(false)
.setAutoCancel(true);
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
if (prefs.getBoolean("share_notification_preference", true)) {
anotherBuilder.setDefaults(Notification.DEFAULT_ALL);
}
try {
notificationManager.notify(notificationId,anotherBuilder.build());
} catch(Exception e) {
//4.1 will throw an exception about not having the VIBRATE permission, ignore it.
//https://android.googlesource.com/platform/frameworks/base/+/android-4.2.1_r1.2%5E%5E!/
}
}
});
Log.e("SendFileActivity", "Failed to send file");
}
});
return np;
} catch (Exception e) {
Log.e("SendFileActivity", "Exception sending files");
e.printStackTrace();
return null;
}
}
@Override
public String[] getSupportedPackageTypes() {
return new String[]{PACKAGE_TYPE_SHARE_REQUEST};

View File

@@ -0,0 +1,120 @@
package org.kde.kdeconnect.Plugins.SharePlugin;
import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.preference.CheckBoxPreference;
import android.preference.Preference;
import android.preference.PreferenceManager;
import android.support.v4.provider.DocumentFile;
import android.util.Log;
import org.kde.kdeconnect.UserInterface.PluginSettingsActivity;
import java.io.File;
public class ShareSettingsActivity extends PluginSettingsActivity {
private final static String PREFERENCE_CUSTOMIZE_DESTINATION = "share_destination_custom";
private final static String PREFERENCE_DESTINATION = "share_destination_folder_uri";
private static final int RESULT_PICKER = Activity.RESULT_FIRST_USER;
private Preference filePicker;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final CheckBoxPreference customDownloads = (CheckBoxPreference) findPreference("share_destination_custom");
filePicker = findPreference("share_destination_folder_preference");
if ((Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)) {
customDownloads.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
updateFilePickerStatus((Boolean) newValue);
return true;
}
});
filePicker.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference preference) {
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
startActivityForResult(intent, RESULT_PICKER);
return true;
}
});
} else {
customDownloads.setEnabled(false);
filePicker.setEnabled(false);
}
boolean customized = PreferenceManager.getDefaultSharedPreferences(this).getBoolean(PREFERENCE_CUSTOMIZE_DESTINATION, false);
updateFilePickerStatus(customized);
}
void updateFilePickerStatus(boolean enabled) {
filePicker.setEnabled(enabled);
String path = PreferenceManager.getDefaultSharedPreferences(this).getString(PREFERENCE_DESTINATION, null);
if (enabled && path != null) {
filePicker.setSummary(Uri.parse(path).getPath());
} else {
filePicker.setSummary(getDefaultDestinationDirectory().getAbsolutePath());
}
}
public static File getDefaultDestinationDirectory() {
return Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
}
public static boolean isCustomDestinationEnabled(Context context) {
return PreferenceManager.getDefaultSharedPreferences(context).getBoolean(PREFERENCE_CUSTOMIZE_DESTINATION, false);
}
//Will return the appropriate directory, whether it is customized or not
public static DocumentFile getDestinationDirectory(Context context) {
if (PreferenceManager.getDefaultSharedPreferences(context).getBoolean(PREFERENCE_CUSTOMIZE_DESTINATION, false)) {
String path = PreferenceManager.getDefaultSharedPreferences(context).getString(PREFERENCE_DESTINATION, null);
if (path != null) {
//There should be no way to enter here on api level < kitkat
DocumentFile treeDocumentFile = DocumentFile.fromTreeUri(context, Uri.parse(path));
if (treeDocumentFile.canWrite()) { //Checks for FLAG_DIR_SUPPORTS_CREATE on directories
return treeDocumentFile;
} else {
//Maybe permission was revoked
Log.w("SharePlugin", "Share destination is not writable, falling back to default path.");
}
}
}
return DocumentFile.fromFile(getDefaultDestinationDirectory());
}
@TargetApi(Build.VERSION_CODES.KITKAT)
@Override
public void onActivityResult(int requestCode, int resultCode, Intent resultData) {
if (requestCode == RESULT_PICKER
&& resultCode == Activity.RESULT_OK
&& resultData != null) {
Uri uri = resultData.getData();
getContentResolver().takePersistableUriPermission(uri, Intent.FLAG_GRANT_READ_URI_PERMISSION |
Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
Preference filePicker = findPreference("share_destination_folder_preference");
filePicker.setSummary(uri.getPath());
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
prefs.edit().putString(PREFERENCE_DESTINATION, uri.toString()).apply();
}
}
}

View File

@@ -23,6 +23,8 @@ package org.kde.kdeconnect.Plugins.TelepathyPlugin;
import android.telephony.SmsManager;
import android.util.Log;
import java.util.ArrayList;
import org.kde.kdeconnect.NetworkPackage;
import org.kde.kdeconnect.Plugins.Plugin;
import org.kde.kdeconnect.Plugins.TelephonyPlugin.TelephonyPlugin;
@@ -64,7 +66,13 @@ public class TelepathyPlugin extends Plugin {
String sms = np.getString("messageBody");
try {
SmsManager smsManager = SmsManager.getDefault();
smsManager.sendTextMessage(phoneNo, null, sms, null, null);
ArrayList<String> parts = smsManager.divideMessage(sms);
// If this message turns out to fit in a single SMS, sendMultpartTextMessage
// properly handles that case
smsManager.sendMultipartTextMessage(phoneNo, null, parts, null, null);
//TODO: Notify other end
} catch (Exception e) {
//TODO: Notify other end

View File

@@ -34,8 +34,10 @@ import android.util.Log;
import org.kde.kdeconnect.Helpers.ContactsHelper;
import org.kde.kdeconnect.NetworkPackage;
import org.kde.kdeconnect.Plugins.Plugin;
import org.kde.kdeconnect_tp.BuildConfig;
import org.kde.kdeconnect_tp.R;
import java.util.ArrayList;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
@@ -72,11 +74,19 @@ public class TelephonyPlugin extends Plugin {
final Bundle bundle = intent.getExtras();
if (bundle == null) return;
final Object[] pdus = (Object[]) bundle.get("pdus");
ArrayList<SmsMessage> messages = new ArrayList<SmsMessage>();
for (Object pdu : pdus) {
SmsMessage message = SmsMessage.createFromPdu((byte[])pdu);
smsBroadcastReceived(message);
// I hope, but am not sure, that the pdus array is in the order that the parts
// of the SMS message should be
// If it is not, I belive the pdu contains the information necessary to put it
// in order, but in my testing the order seems to be correct, so I won't worry
// about it now.
messages.add(SmsMessage.createFromPdu((byte[])pdu));
}
smsBroadcastReceived(messages);
} else if (TelephonyManager.ACTION_PHONE_STATE_CHANGED.equals(action)) {
String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE);
@@ -194,7 +204,14 @@ public class TelephonyPlugin extends Plugin {
lastState = state;
}
private void smsBroadcastReceived(SmsMessage message) {
private void smsBroadcastReceived(ArrayList<SmsMessage> messages) {
if (BuildConfig.DEBUG) {
if (!(messages.size() > 0))
{
throw new AssertionError("This method requires at least one message");
}
}
//Log.e("SmsBroadcastReceived", message.toString());
@@ -202,12 +219,18 @@ public class TelephonyPlugin extends Plugin {
np.set("event","sms");
String messageBody = message.getMessageBody();
String messageBody = new String();
for (int index = 0; index < messages.size(); index ++)
{
messageBody += messages.get(index).getMessageBody();
}
if (messageBody != null) {
np.set("messageBody",messageBody);
}
String phoneNumber = message.getOriginatingAddress();
String phoneNumber = messages.get(0).getOriginatingAddress();
Map<String, String> contactInfo = ContactsHelper.phoneNumberLookup(context, phoneNumber);
if (phoneNumber != null) {
np.set("phoneNumber", phoneNumber);

View File

@@ -23,10 +23,10 @@ package org.kde.kdeconnect.UserInterface;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Build;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.v7.app.ActionBarActivity;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.view.inputmethod.EditorInfo;
@@ -82,10 +82,15 @@ public class CustomDevicesActivity extends ActionBarActivity {
});
}
boolean dialogAlreadyShown = false;
private AdapterView.OnItemClickListener onClickListener = new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, final int position, final long id) {
Log.i(LOG_ID, "Item clicked pos: " + position + " id: " + id);
if (dialogAlreadyShown) {
return;
}
// remove touched item after confirmation
DialogInterface.OnClickListener confirmationListener = new DialogInterface.OnClickListener() {
@Override
@@ -93,7 +98,6 @@ public class CustomDevicesActivity extends ActionBarActivity {
switch (which) {
case DialogInterface.BUTTON_POSITIVE:
ipAddressList.remove(position);
Log.i(LOG_ID, "Removed item pos: " + position + " id: " + id);
saveList();
break;
case DialogInterface.BUTTON_NEGATIVE:
@@ -101,12 +105,23 @@ public class CustomDevicesActivity extends ActionBarActivity {
}
}
};
AlertDialog.Builder builder = new AlertDialog.Builder(CustomDevicesActivity.this);
builder.setMessage("Delete " + ipAddressList.get(position) + " ?");
builder.setPositiveButton("Yes", confirmationListener);
builder.setNegativeButton("No", confirmationListener);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { //DismissListener
dialogAlreadyShown = true;
builder.setOnDismissListener(new DialogInterface.OnDismissListener() {
@Override
public void onDismiss(DialogInterface dialog) {
dialogAlreadyShown = false;
}
});
}
builder.show();
((ArrayAdapter) list.getAdapter()).notifyDataSetChanged();
}
};
@@ -143,37 +158,32 @@ public class CustomDevicesActivity extends ActionBarActivity {
}
public static String serializeIpList(ArrayList<String> iplist) {
public static String serializeIpList(ArrayList<String> ipList) {
String serialized = "";
for (String ipaddr : iplist) {
serialized += IP_DELIM+ipaddr;
for (String ipAddress : ipList) {
serialized += IP_DELIM+ipAddress;
}
// remove first delimiter
serialized = serialized.substring(IP_DELIM.length());
Log.d(LOG_ID, serialized);
return serialized;
}
public static ArrayList<String> deserializeIpList(String serialized) {
ArrayList<String> iplist = new ArrayList<>();
Log.d(LOG_ID, serialized);
for (String ipaddr : serialized.split(IP_DELIM)) {
iplist.add(ipaddr);
Log.d(LOG_ID, ipaddr);
ArrayList<String> ipList = new ArrayList<>();
for (String ipAddress : serialized.split(IP_DELIM)) {
ipList.add(ipAddress);
}
return iplist;
return ipList;
}
private void initializeDeviceList(Context context){
String deviceListPrefs = PreferenceManager.getDefaultSharedPreferences(context).getString(
KEY_CUSTOM_DEVLIST_PREFERENCE, "");
if(deviceListPrefs.isEmpty()){
Log.i(LOG_ID, "Initialising empty custom device list");
PreferenceManager.getDefaultSharedPreferences(context).edit().putString(
KEY_CUSTOM_DEVLIST_PREFERENCE,
deviceListPrefs).commit();
} else {
Log.i(LOG_ID, "Populating device list");
ipAddressList = deserializeIpList(deviceListPrefs);
}
}

View File

@@ -40,6 +40,7 @@ import android.widget.TextView;
import org.kde.kdeconnect.BackgroundService;
import org.kde.kdeconnect.Device;
import org.kde.kdeconnect.Helpers.NetworkHelper;
import org.kde.kdeconnect.Helpers.SecurityHelpers.SslHelper;
import org.kde.kdeconnect.Plugins.Plugin;
import org.kde.kdeconnect.UserInterface.List.CustomItem;
@@ -60,14 +61,15 @@ import java.util.concurrent.ConcurrentHashMap;
*/
public class DeviceFragment extends Fragment {
private static final String ARG_DEVICE_ID = "deviceId";
private View rootView;
static private String mDeviceId; //Static because if we get here by using the back button in the action bar, the extra deviceId will not be set.
private Device device;
static final String ARG_DEVICE_ID = "deviceId";
private TextView errorHeader;
View rootView;
static String mDeviceId; //Static because if we get here by using the back button in the action bar, the extra deviceId will not be set.
Device device;
private MaterialActivity mActivity;
TextView errorHeader;
MaterialActivity mActivity;
public DeviceFragment() { }
@@ -84,6 +86,13 @@ public class DeviceFragment extends Fragment {
this.setArguments(args);
}
public DeviceFragment(String deviceId, MaterialActivity activity){
this.mActivity = activity;
Bundle args = new Bundle();
args.putString(ARG_DEVICE_ID, deviceId);
this.setArguments(args);
}
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
@@ -122,10 +131,6 @@ public class DeviceFragment extends Fragment {
refreshUI();
//TODO: Is this needed?
//if (!device.hasPluginsLoaded() && device.isReachable()) {
// device.reloadPluginsFromSettings();
//}
}
});
@@ -183,8 +188,7 @@ public class DeviceFragment extends Fragment {
return rootView;
}
private final Device.PluginsChangedListener pluginsChangedListener = new Device.PluginsChangedListener() {
final Device.PluginsChangedListener pluginsChangedListener = new Device.PluginsChangedListener() {
@Override
public void onPluginsChanged(final Device device) {
refreshUI();
@@ -289,21 +293,6 @@ public class DeviceFragment extends Fragment {
public void onResume() {
super.onResume();
//TODO: Is this needed?
/*
BackgroundService.RunCommand(mActivity, new BackgroundService.InstanceCallback() {
@Override
public void onServiceStart(BackgroundService service) {
if (mDeviceId != null) {
Device device = service.getDevice(mDeviceId);
if (device != null && device.isReachable()) {
device.reloadPluginsFromSettings();
}
}
}
});
*/
getView().setFocusableInTouchMode(true);
getView().requestFocus();
getView().setOnKeyListener(new View.OnKeyListener() {
@@ -345,9 +334,11 @@ public class DeviceFragment extends Fragment {
boolean paired = device.isPaired();
boolean reachable = device.isReachable();
boolean onData = NetworkHelper.isOnMobileNetwork(getContext());
rootView.findViewById(R.id.pairing_buttons).setVisibility(paired ? View.GONE : View.VISIBLE);
rootView.findViewById(R.id.unpair_message).setVisibility((paired && !reachable) ? View.VISIBLE : View.GONE);
rootView.findViewById(R.id.not_reachable_message).setVisibility((paired && !reachable && !onData) ? View.VISIBLE : View.GONE);
rootView.findViewById(R.id.on_data_message).setVisibility((paired && !reachable && onData) ? View.VISIBLE : View.GONE);
try {
ArrayList<ListAdapter.Item> items = new ArrayList<>();
@@ -418,7 +409,7 @@ public class DeviceFragment extends Fragment {
}
private final Device.PairingCallback pairingCallback = new Device.PairingCallback() {
final Device.PairingCallback pairingCallback = new Device.PairingCallback() {
@Override
public void incomingRequest() {
@@ -435,6 +426,7 @@ public class DeviceFragment extends Fragment {
mActivity.runOnUiThread(new Runnable() {
@Override
public void run() {
if (rootView == null) return;
((TextView) rootView.findViewById(R.id.pair_message)).setText(error);
rootView.findViewById(R.id.pair_progress).setVisibility(View.GONE);
rootView.findViewById(R.id.pair_button).setVisibility(View.VISIBLE);
@@ -449,6 +441,7 @@ public class DeviceFragment extends Fragment {
mActivity.runOnUiThread(new Runnable() {
@Override
public void run() {
if (rootView == null) return;
((TextView) rootView.findViewById(R.id.pair_message)).setText(R.string.device_not_paired);
rootView.findViewById(R.id.pair_progress).setVisibility(View.GONE);
rootView.findViewById(R.id.pair_button).setVisibility(View.VISIBLE);
@@ -460,4 +453,45 @@ public class DeviceFragment extends Fragment {
};
public static void acceptPairing(final String devId, final MaterialActivity activity){
final DeviceFragment frag = new DeviceFragment(devId, activity);
BackgroundService.RunCommand(activity, new BackgroundService.InstanceCallback() {
public void onServiceStart(BackgroundService service) {
Device dev = service.getDevice(devId);
activity.getSupportActionBar().setTitle(dev.getName());
dev.addPairingCallback(frag.pairingCallback);
dev.addPluginsChangedListener(frag.pluginsChangedListener);
frag.device = dev;
frag.device.acceptPairing();
frag.refreshUI();
}
});
}
public static void rejectPairing(final String devId, final MaterialActivity activity){
final DeviceFragment frag = new DeviceFragment(devId, activity);
BackgroundService.RunCommand(activity, new BackgroundService.InstanceCallback() {
public void onServiceStart(BackgroundService service) {
Device dev = service.getDevice(devId);
activity.getSupportActionBar().setTitle(dev.getName());
dev.addPairingCallback(frag.pairingCallback);
dev.addPluginsChangedListener(frag.pluginsChangedListener);
frag.device = dev;
//Remove listener so buttons don't show for a while before changing the view
frag.device.removePluginsChangedListener(frag.pluginsChangedListener);
frag.device.removePairingCallback(frag.pairingCallback);
frag.device.rejectPairing();
activity.onDeviceSelected(null);
frag.refreshUI();
}
});
}
}

Some files were not shown because too many files have changed in this diff Show More