Compare commits
194 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
debbe4fe2c | ||
|
5724a66561 | ||
|
91fe9d63b0 | ||
|
a90928188a | ||
|
256ca60036 | ||
|
05fd6fe5b0 | ||
|
6b9a691f24 | ||
|
d18b61f2a1 | ||
|
6448258648 | ||
|
e5e9490f19 | ||
|
9f7c5be533 | ||
|
f690105181 | ||
|
dafe9eb023 | ||
|
cfbe6775d0 | ||
|
6365143c2c | ||
|
f3fbe4d035 | ||
|
2862e5164e | ||
|
6fae1d350d | ||
|
647f71bf98 | ||
|
343b2ed5e8 | ||
|
eb7351a803 | ||
|
7e7d6c4d82 | ||
|
59d01763c7 | ||
|
5b2756b7f8 | ||
|
5912611aab | ||
|
54d24848e5 | ||
|
638c9df328 | ||
|
9943c36877 | ||
|
03bcfecb88 | ||
|
1b4ade0ae1 | ||
|
b9890210ad | ||
|
1509bfaf6d | ||
|
a22ffd611a | ||
|
adb88560b5 | ||
|
03ede77bd1 | ||
|
6afbe93c2d | ||
|
dd4421dce2 | ||
|
262f811bba | ||
|
0b52cbe36f | ||
|
8542aaf4fa | ||
|
c9d11f650c | ||
|
6c5ed3094b | ||
|
5aaec15e79 | ||
|
b0a632fe10 | ||
|
4d1464484e | ||
|
d6cc84ccfb | ||
|
624cee5d87 | ||
|
a8664d01ec | ||
|
bd68f71af6 | ||
|
8ec828d6e4 | ||
|
a44d48d527 | ||
|
804642c5fc | ||
|
8e0daa69cc | ||
|
400b35216d | ||
|
4a5545529a | ||
|
b2fa8ab506 | ||
|
b9a0b3d2f0 | ||
|
e8c6784ce0 | ||
|
e3b8bb5ffc | ||
|
103bc69347 | ||
|
2b45c82a2e | ||
|
0d3232a5a1 | ||
|
ed5ddc37c8 | ||
|
48bc56f52a | ||
|
5de10b05e7 | ||
|
1fe2590ec8 | ||
|
d02684c714 | ||
|
80ed8a58d5 | ||
|
962501fe38 | ||
|
60c1e67e66 | ||
|
318b82941f | ||
|
acdf8d467e | ||
|
ceee1ee1f6 | ||
|
071f71cb9c | ||
|
4adf2cfbbd | ||
|
de4fa31b2a | ||
|
4deba4ea4f | ||
|
07a8b107eb | ||
|
3b750c78ab | ||
|
47790a710a | ||
|
92451df32f | ||
|
55eada9dfc | ||
|
0ed73f6729 | ||
|
c8e24bf07d | ||
|
f016a06c32 | ||
|
23463afc33 | ||
|
45fd3f88e8 | ||
|
b54e2ea36e | ||
|
3043ca5d05 | ||
|
47368a27fd | ||
|
046a1cb676 | ||
|
43c6742e21 | ||
|
5b2f863e0e | ||
|
a12e64ca59 | ||
|
e99ba38eac | ||
|
0730c52741 | ||
|
093b722f00 | ||
|
162fc8b8dd | ||
|
c648185ffa | ||
|
af915b5756 | ||
|
dc60968a35 | ||
|
c122a0d2f3 | ||
|
ce597f2e51 | ||
|
7ae687ae11 | ||
|
53bb376990 | ||
|
cc10538dcb | ||
|
9c7aaf2ed9 | ||
|
0283b0112e | ||
|
906fc35abb | ||
|
8bc3e69ce6 | ||
|
020d2bca2a | ||
|
50682935e0 | ||
|
1da74a6c68 | ||
|
aa33f4cd08 | ||
|
0c142928f9 | ||
|
24aefebb0e | ||
|
7a47bd0b9c | ||
|
cbb3787a15 | ||
|
61048e5df4 | ||
|
8644f7ee15 | ||
|
77f9a30bd3 | ||
|
1dbc93ec73 | ||
|
64c5362b1c | ||
|
0c4ae62061 | ||
|
727c845624 | ||
|
577d9a5dc8 | ||
|
0311163829 | ||
|
76fd6d1e08 | ||
|
a79e8f83ce | ||
|
3f6ec6a2d7 | ||
|
726f623eea | ||
|
0db8f7c1d4 | ||
|
7a289fbe38 | ||
|
41bb2ed916 | ||
|
4598f080a2 | ||
|
ecf22e889b | ||
|
8598cf5f2e | ||
|
1def9cc9ce | ||
|
0772a37f4e | ||
|
16edb35a0e | ||
|
8f9bad7a0f | ||
|
4fd96062f6 | ||
|
a0a9eca060 | ||
|
5999ef7c8e | ||
|
9542597424 | ||
|
11e5563d9a | ||
|
f31afdb6d0 | ||
|
27ec7c5bfb | ||
|
49360816a3 | ||
|
dd364bd562 | ||
|
809f37a541 | ||
|
36c3df7a07 | ||
|
34aec7120e | ||
|
0a494b002d | ||
|
7298247dfc | ||
|
72a97d9e1c | ||
|
7cc80baf16 | ||
|
0600b1ee2e | ||
|
2f0059938d | ||
|
a023316609 | ||
|
d94ed56c4e | ||
|
15a11cce02 | ||
|
36530b9580 | ||
|
f54acd7308 | ||
|
cfe9ccdc31 | ||
|
52c7581f42 | ||
|
a57dc71ad1 | ||
|
77d06cfe77 | ||
|
13a7c1e5fe | ||
|
5ccf215a54 | ||
|
fddf3c64b5 | ||
|
fb02b9bdf1 | ||
|
8453156d16 | ||
|
9bbe2908ed | ||
|
fb843f8789 | ||
|
c85619dfd2 | ||
|
de9f78adf3 | ||
|
9021ab9454 | ||
|
10210b3972 | ||
|
f83b9cbe0c | ||
|
7d821e7c88 | ||
|
02070343fe | ||
|
416a000dd3 | ||
|
a15cad9ec5 | ||
|
e98100f5f0 | ||
|
d19e7d2052 | ||
|
4e02c674f8 | ||
|
6aa49757fc | ||
|
3c10312d15 | ||
|
26e3363b30 | ||
|
4033233ec1 | ||
|
34e53576e1 | ||
|
a15d76c588 | ||
|
1acea73383 |
3
.reviewboardrc
Normal file
@@ -0,0 +1,3 @@
|
||||
REVIEWBOARD_URL = "https://git.reviewboard.kde.org"
|
||||
REPOSITORY = 'git://anongit.kde.org/kdeconnect-android'
|
||||
TARGET_GROUPS = 'kdeconnect'
|
31
build.gradle
@@ -1,29 +1,44 @@
|
||||
buildscript {
|
||||
repositories {
|
||||
mavenCentral()
|
||||
jcenter()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:0.6.+'
|
||||
classpath 'com.android.tools.build:gradle:0.12.+'
|
||||
}
|
||||
}
|
||||
|
||||
apply plugin: 'android'
|
||||
apply plugin: 'com.android.application'
|
||||
|
||||
android {
|
||||
compileSdkVersion 19
|
||||
buildToolsVersion "19"
|
||||
|
||||
buildToolsVersion '20.0.0'
|
||||
defaultConfig {
|
||||
minSdkVersion 9
|
||||
targetSdkVersion 19
|
||||
}
|
||||
packagingOptions {
|
||||
exclude "META-INF/DEPENDENCIES"
|
||||
exclude "META-INF/NOTICE"
|
||||
exclude "META-INF/LICENSE"
|
||||
exclude "META-INF/LICENSE.txt"
|
||||
exclude "META-INF/NOTICE.txt"
|
||||
}
|
||||
lintOptions {
|
||||
abortOnError false
|
||||
}
|
||||
buildTypes {
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
compile "com.android.support:support-v4:19.0.+"
|
||||
compile "com.android.support:appcompat-v7:19.0.+"
|
||||
compile "org.apache.mina:mina-core:2.0.+"
|
||||
compile 'com.android.support:support-v4:19.1.+'
|
||||
compile 'com.android.support:appcompat-v7:19.1.+'
|
||||
compile 'org.apache.mina:mina-core:2.0.+'
|
||||
compile 'org.bouncycastle:bcprov-jdk16:1.45'
|
||||
compile 'org.apache.sshd:sshd-core:0.8.0'
|
||||
compile 'tomcat:tomcat-apr:5.5.+'
|
||||
//compile fileTree(dir: 'libs', include: '*.jar')
|
||||
}
|
||||
|
4
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -1,6 +1,6 @@
|
||||
#Tue Oct 29 15:58:14 CET 2013
|
||||
#Mon Jun 09 09:51:48 CEST 2014
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=http\://services.gradle.org/distributions/gradle-1.8-all.zip
|
||||
distributionUrl=http\://services.gradle.org/distributions/gradle-1.12-all.zip
|
||||
|
1067
icon.svg
Normal file
After Width: | Height: | Size: 35 KiB |
@@ -1,13 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$" external.system.id="GRADLE" type="JAVA_MODULE" version="4">
|
||||
<module external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$" external.system.id="GRADLE" external.system.module.group="" external.system.module.version="unspecified" type="JAVA_MODULE" version="4">
|
||||
<component name="FacetManager">
|
||||
<facet type="android" name="Android">
|
||||
<configuration>
|
||||
<option name="SELECTED_BUILD_VARIANT" value="Debug" />
|
||||
<option name="SELECTED_BUILD_VARIANT" value="debug" />
|
||||
<option name="ASSEMBLE_TASK_NAME" value="assembleDebug" />
|
||||
<option name="COMPILE_JAVA_TASK_NAME" value="compileDebug" />
|
||||
<option name="ASSEMBLE_TEST_TASK_NAME" value="assembleTest" />
|
||||
<option name="COMPILE_JAVA_TASK_NAME" value="compileDebugJava" />
|
||||
<option name="ASSEMBLE_TEST_TASK_NAME" value="assembleDebugTest" />
|
||||
<option name="SOURCE_GEN_TASK_NAME" value="generateDebugSources" />
|
||||
<option name="TEST_SOURCE_GEN_TASK_NAME" value="generateDebugTestSources" />
|
||||
<option name="ALLOW_USER_CONFIGURATION" value="false" />
|
||||
<option name="MANIFEST_FILE_RELATIVE_PATH" value="/src/main/AndroidManifest.xml" />
|
||||
<option name="RES_FOLDER_RELATIVE_PATH" value="/src/main/res" />
|
||||
@@ -22,60 +23,70 @@
|
||||
</facet>
|
||||
</component>
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="false">
|
||||
<output url="file://$MODULE_DIR$/build/classes/debug" />
|
||||
<output url="file://$MODULE_DIR$/build/intermediates/classes/debug" />
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/source/r/debug" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/source/aidl/debug" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/source/rs/debug" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/source/buildConfig/debug" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/res/rs/debug" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/source/r/test" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/source/aidl/test" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/source/rs/test" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/source/buildConfig/test" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/res/rs/test" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/r/debug" isTestSource="false" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/aidl/debug" isTestSource="false" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/debug" isTestSource="false" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/rs/debug" isTestSource="false" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/debug" type="java-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/r/test/debug" isTestSource="true" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/aidl/test/debug" isTestSource="true" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/test/debug" isTestSource="true" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/rs/test/debug" isTestSource="true" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/test/debug" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/res" type="java-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/resources" type="java-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/assets" type="java-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/aidl" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/assets" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/java" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/jni" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/rs" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/res" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/resources" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/res" type="java-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/assets" type="java-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/aidl" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/assets" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/jni" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/rs" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/res" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/resources" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/instrumentTest/aidl" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/instrumentTest/assets" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/instrumentTest/java" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/instrumentTest/jni" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/instrumentTest/rs" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/instrumentTest/res" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/instrumentTest/resources" isTestSource="true" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/.git" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/.gradle" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/.idea" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/apk" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/assets" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/bundles" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/classes" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/dependency-cache" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/incremental" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/libs" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/manifests" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/symbols" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/tmp" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/res" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/resources" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/assets" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/aidl" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/java" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/jni" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/rs" isTestSource="true" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/assets" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/bundles" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/classes" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/coverage-instrumented-classes" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/dependency-cache" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/dex" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/dex-cache" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/jacoco" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/javaResources" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/libs" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/lint" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/manifests" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/ndk" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/pre-dexed" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/proguard" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/res" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/rs" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/symbols" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/outputs" />
|
||||
</content>
|
||||
<orderEntry type="jdk" jdkName="Android API 19 Platform" jdkType="Android SDK" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="library" exported="" name="support-v4-19.1.0" level="project" />
|
||||
<orderEntry type="library" exported="" name="sshd-core-0.8.0" level="project" />
|
||||
<orderEntry type="library" exported="" name="bcprov-jdk16-1.45" level="project" />
|
||||
<orderEntry type="library" exported="" name="appcompat-v7-19.1.0" level="project" />
|
||||
<orderEntry type="library" exported="" name="mina-core-2.0.8" level="project" />
|
||||
<orderEntry type="library" exported="" name="tomcat-apr-5.5.15" level="project" />
|
||||
<orderEntry type="library" exported="" name="slf4j-api-1.6.6" level="project" />
|
||||
<orderEntry type="library" exported="" name="support-v4-19.0.0" level="project" />
|
||||
<orderEntry type="library" exported="" name="mina-core-2.0.7" level="project" />
|
||||
<orderEntry type="library" exported="" name="ComAndroidSupportAppcompatV71900.aar" level="project" />
|
||||
</component>
|
||||
</module>
|
||||
|
||||
|
@@ -1,11 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="org.kde.kdeconnect_tp"
|
||||
android:versionCode="10"
|
||||
android:versionName="0.4.1">
|
||||
android:versionCode="732"
|
||||
android:versionName="0.7.3.2">
|
||||
|
||||
<uses-sdk android:minSdkVersion="9"
|
||||
android:targetSdkVersion="18" />
|
||||
android:targetSdkVersion="19" />
|
||||
|
||||
<supports-screens
|
||||
android:smallScreens="true"
|
||||
@@ -25,6 +25,8 @@
|
||||
<uses-permission android:name="android.permission.BATTERY_STATS" />
|
||||
<uses-permission android:name="android.permission.RECEIVE_SMS" android:required="false" />
|
||||
<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"/>
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
@@ -86,6 +88,15 @@
|
||||
android:value="org.kde.kdeconnect.UserInterface.DeviceActivity" />
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name="org.kde.kdeconnect.UserInterface.PluginSettingsActivity"
|
||||
android:label="@string/mpris_settings"
|
||||
android:parentActivityName="org.kde.kdeconnect.UserInterface.SettingsActivity"
|
||||
>
|
||||
<meta-data android:name="android.support.PARENT_ACTIVITY"
|
||||
android:value="org.kde.kdeconnect.UserInterface.SettingsActivity" />
|
||||
</activity>
|
||||
|
||||
<receiver android:name="org.kde.kdeconnect.KdeConnectBroadcastReceiver">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.PACKAGE_REPLACED" />
|
||||
@@ -123,6 +134,19 @@
|
||||
android:value="org.kde.kdeconnect.UserInterface.DeviceActivity" />
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:theme="@style/Theme.AppCompat"
|
||||
android:name="org.kde.kdeconnect.Plugins.MousePadPlugin.MousePadActivity"
|
||||
android:label="@string/remote_control"
|
||||
android:windowSoftInputMode="stateHidden|adjustResize"
|
||||
android:configChanges="orientation|keyboardHidden|screenSize"
|
||||
android:screenOrientation="fullSensor"
|
||||
android:parentActivityName="org.kde.kdeconnect.UserInterface.DeviceActivity"
|
||||
>
|
||||
<meta-data android:name="android.support.PARENT_ACTIVITY"
|
||||
android:value="org.kde.kdeconnect.UserInterface.DeviceActivity" />
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:theme="@style/Theme.AppCompat"
|
||||
android:name="org.kde.kdeconnect.UserInterface.ShareToReceiver"
|
||||
|
@@ -1,23 +1,17 @@
|
||||
package org.kde.kdeconnect.Backends;
|
||||
|
||||
import android.content.SharedPreferences;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.util.Base64;
|
||||
|
||||
import org.kde.kdeconnect.NetworkPackage;
|
||||
|
||||
import java.security.KeyFactory;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.PublicKey;
|
||||
import java.security.spec.PKCS8EncodedKeySpec;
|
||||
import java.util.ArrayList;
|
||||
|
||||
|
||||
public abstract class BaseLink {
|
||||
|
||||
private BaseLinkProvider linkProvider;
|
||||
private String deviceId;
|
||||
private ArrayList<PackageReceiver> receivers = new ArrayList<PackageReceiver>();
|
||||
private final BaseLinkProvider linkProvider;
|
||||
private final String deviceId;
|
||||
private final ArrayList<PackageReceiver> receivers = new ArrayList<PackageReceiver>();
|
||||
protected PrivateKey privateKey;
|
||||
|
||||
protected BaseLink(String deviceId, BaseLinkProvider linkProvider) {
|
||||
|
@@ -9,7 +9,7 @@ import java.util.ArrayList;
|
||||
|
||||
public abstract class BaseLinkProvider {
|
||||
|
||||
private ArrayList<ConnectionReceiver> connectionReceivers = new ArrayList<ConnectionReceiver>();
|
||||
private final ArrayList<ConnectionReceiver> connectionReceivers = new ArrayList<ConnectionReceiver>();
|
||||
|
||||
public interface ConnectionReceiver {
|
||||
public void onConnectionReceived(NetworkPackage identityPackage, BaseLink link);
|
||||
@@ -43,7 +43,7 @@ public abstract class BaseLinkProvider {
|
||||
public abstract void onStop();
|
||||
public abstract void onNetworkChange();
|
||||
|
||||
public abstract int getPriority();
|
||||
//public abstract int getPriority();
|
||||
public abstract String getName();
|
||||
|
||||
}
|
||||
|
@@ -3,6 +3,7 @@ package org.kde.kdeconnect.Backends.LanBackend;
|
||||
import android.content.Context;
|
||||
import android.os.AsyncTask;
|
||||
import android.util.Log;
|
||||
import android.support.v4.util.LongSparseArray;
|
||||
|
||||
import org.apache.mina.core.future.ConnectFuture;
|
||||
import org.apache.mina.core.future.IoFuture;
|
||||
@@ -30,9 +31,9 @@ public class LanLinkProvider extends BaseLinkProvider {
|
||||
|
||||
private final static int port = 1714;
|
||||
|
||||
private Context context;
|
||||
private HashMap<String, LanLink> visibleComputers = new HashMap<String, LanLink>();
|
||||
private HashMap<Long, LanLink> nioSessions = new HashMap<Long, LanLink>();
|
||||
private final Context context;
|
||||
private final HashMap<String, LanLink> visibleComputers = new HashMap<String, LanLink>();
|
||||
private final LongSparseArray<LanLink> nioSessions = new LongSparseArray<LanLink>();
|
||||
|
||||
private NioSocketAcceptor tcpAcceptor = null;
|
||||
private NioDatagramAcceptor udpAcceptor = null;
|
||||
@@ -41,8 +42,9 @@ public class LanLinkProvider extends BaseLinkProvider {
|
||||
@Override
|
||||
public void sessionClosed(IoSession session) throws Exception {
|
||||
|
||||
LanLink brokenLink = nioSessions.remove(session.getId());
|
||||
LanLink brokenLink = nioSessions.get(session.getId());
|
||||
if (brokenLink != null) {
|
||||
nioSessions.remove(session.getId());
|
||||
connectionLost(brokenLink);
|
||||
brokenLink.disconnect();
|
||||
String deviceId = brokenLink.getDeviceId();
|
||||
@@ -92,7 +94,7 @@ public class LanLinkProvider extends BaseLinkProvider {
|
||||
}
|
||||
};
|
||||
|
||||
private IoHandler udpHandler = new IoHandlerAdapter() {
|
||||
private final IoHandler udpHandler = new IoHandlerAdapter() {
|
||||
@Override
|
||||
public void messageReceived(IoSession udpSession, Object message) throws Exception {
|
||||
super.messageReceived(udpSession, message);
|
||||
@@ -165,6 +167,10 @@ public class LanLinkProvider extends BaseLinkProvider {
|
||||
String deviceId = identityPackage.getString("deviceId");
|
||||
Log.i("LanLinkProvider","addLink to "+deviceId);
|
||||
LanLink oldLink = visibleComputers.get(deviceId);
|
||||
if (oldLink == link) {
|
||||
Log.e("KDEConnect", "LanLinkProvider: oldLink == link. This should not happen!");
|
||||
return;
|
||||
}
|
||||
visibleComputers.put(deviceId, link);
|
||||
connectionAccepted(identityPackage, link);
|
||||
if (oldLink != null) {
|
||||
@@ -261,25 +267,21 @@ public class LanLinkProvider extends BaseLinkProvider {
|
||||
|
||||
@Override
|
||||
public void onNetworkChange() {
|
||||
|
||||
onStop();
|
||||
onStart();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStop() {
|
||||
|
||||
udpAcceptor.unbind();
|
||||
tcpAcceptor.unbind();
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
@Override
|
||||
public int getPriority() {
|
||||
return 1000;
|
||||
}
|
||||
|
||||
*/
|
||||
@Override
|
||||
public String getName() {
|
||||
return "LanLinkProvider";
|
||||
|
@@ -7,7 +7,7 @@ import org.kde.kdeconnect.NetworkPackage;
|
||||
|
||||
public class LoopbackLinkProvider extends BaseLinkProvider {
|
||||
|
||||
private Context context;
|
||||
private final Context context;
|
||||
|
||||
public LoopbackLinkProvider(Context context) {
|
||||
this.context = context;
|
||||
@@ -20,22 +20,19 @@ public class LoopbackLinkProvider extends BaseLinkProvider {
|
||||
|
||||
@Override
|
||||
public void onStop() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNetworkChange() {
|
||||
|
||||
NetworkPackage np = NetworkPackage.createIdentityPackage(context);
|
||||
connectionAccepted(np, new LoopbackLink(this));
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
@Override
|
||||
public int getPriority() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
*/
|
||||
@Override
|
||||
public String getName() {
|
||||
return "LoopbackLinkProvider";
|
||||
|
@@ -26,11 +26,11 @@ import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
public class BackgroundService extends Service {
|
||||
|
||||
private ArrayList<BaseLinkProvider> linkProviders = new ArrayList<BaseLinkProvider>();
|
||||
private final ArrayList<BaseLinkProvider> linkProviders = new ArrayList<BaseLinkProvider>();
|
||||
|
||||
private HashMap<String, Device> devices = new HashMap<String, Device>();
|
||||
private final HashMap<String, Device> devices = new HashMap<String, Device>();
|
||||
|
||||
private Device.PairingCallback devicePairingCallback = new Device.PairingCallback() {
|
||||
private final Device.PairingCallback devicePairingCallback = new Device.PairingCallback() {
|
||||
@Override
|
||||
public void incomingRequest() {
|
||||
if (deviceListChangedCallback != null) deviceListChangedCallback.onDeviceListChanged();
|
||||
@@ -63,7 +63,7 @@ public class BackgroundService extends Service {
|
||||
}
|
||||
}
|
||||
|
||||
public void registerLinkProviders() {
|
||||
private void registerLinkProviders() {
|
||||
|
||||
SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
|
||||
@@ -81,7 +81,7 @@ public class BackgroundService extends Service {
|
||||
return devices.get(id);
|
||||
}
|
||||
|
||||
private BaseLinkProvider.ConnectionReceiver deviceListener = new BaseLinkProvider.ConnectionReceiver() {
|
||||
private final BaseLinkProvider.ConnectionReceiver deviceListener = new BaseLinkProvider.ConnectionReceiver() {
|
||||
@Override
|
||||
public void onConnectionReceived(final NetworkPackage identityPackage, final BaseLink link) {
|
||||
|
||||
@@ -96,7 +96,6 @@ public class BackgroundService extends Service {
|
||||
device.addLink(identityPackage, link);
|
||||
} else {
|
||||
Log.i("BackgroundService", "addLink,unknown device: " + deviceId);
|
||||
String name = identityPackage.getString("deviceName");
|
||||
device = new Device(BackgroundService.this, identityPackage, link);
|
||||
devices.put(deviceId, device);
|
||||
device.addPairingCallback(devicePairingCallback);
|
||||
@@ -266,14 +265,13 @@ public class BackgroundService extends Service {
|
||||
void onServiceStart(BackgroundService service);
|
||||
}
|
||||
|
||||
private static ArrayList<InstanceCallback> callbacks = new ArrayList<InstanceCallback>();
|
||||
private final static ArrayList<InstanceCallback> callbacks = new ArrayList<InstanceCallback>();
|
||||
|
||||
private static final Lock mutex = new ReentrantLock(true);
|
||||
private final static Lock mutex = new ReentrantLock(true);
|
||||
|
||||
@Override
|
||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||
//This will be called for each intent launch, even if the service is already started and it is reused
|
||||
Log.i("BackgroundService","onStartCommand");
|
||||
mutex.lock();
|
||||
for (InstanceCallback c : callbacks) {
|
||||
c.onServiceStart(this);
|
||||
|
@@ -35,11 +35,11 @@ import java.util.TimerTask;
|
||||
|
||||
public class Device implements BaseLink.PackageReceiver {
|
||||
|
||||
private Context context;
|
||||
private final Context context;
|
||||
|
||||
private String deviceId;
|
||||
private String name;
|
||||
private PublicKey publicKey;
|
||||
private final String deviceId;
|
||||
private final String name;
|
||||
public PublicKey publicKey;
|
||||
private int notificationId;
|
||||
private int protocolVersion;
|
||||
|
||||
@@ -61,11 +61,11 @@ public class Device implements BaseLink.PackageReceiver {
|
||||
private ArrayList<PairingCallback> pairingCallback = new ArrayList<PairingCallback>();
|
||||
private Timer pairingTimer;
|
||||
|
||||
private ArrayList<BaseLink> links = new ArrayList<BaseLink>();
|
||||
private HashMap<String, Plugin> plugins = new HashMap<String, Plugin>();
|
||||
private HashMap<String, Plugin> failedPlugins = new HashMap<String, Plugin>();
|
||||
private final ArrayList<BaseLink> links = new ArrayList<BaseLink>();
|
||||
private final HashMap<String, Plugin> plugins = new HashMap<String, Plugin>();
|
||||
private final HashMap<String, Plugin> failedPlugins = new HashMap<String, Plugin>();
|
||||
|
||||
SharedPreferences settings;
|
||||
private final SharedPreferences settings;
|
||||
|
||||
//Remembered trusted device, we need to wait for a incoming devicelink to communicate
|
||||
Device(Context context, String deviceId) {
|
||||
@@ -209,8 +209,6 @@ public class Device implements BaseLink.PackageReceiver {
|
||||
|
||||
public void unpair() {
|
||||
|
||||
if (!isPaired()) return;
|
||||
|
||||
//Log.e("Device","Unpairing (unpair)");
|
||||
pairStatus = PairStatus.NotPaired;
|
||||
|
||||
@@ -323,12 +321,14 @@ public class Device implements BaseLink.PackageReceiver {
|
||||
|
||||
Log.i("Device","addLink "+link.getLinkProvider().getName()+" -> "+getName() + " active links: "+ links.size());
|
||||
|
||||
/*
|
||||
Collections.sort(links, new Comparator<BaseLink>() {
|
||||
@Override
|
||||
public int compare(BaseLink o, BaseLink o2) {
|
||||
return o2.getLinkProvider().getPriority() - o.getLinkProvider().getPriority();
|
||||
}
|
||||
});
|
||||
*/
|
||||
|
||||
link.addPackageReceiver(this);
|
||||
|
||||
@@ -408,7 +408,7 @@ public class Device implements BaseLink.PackageReceiver {
|
||||
.setTicker(res.getString(R.string.pair_requested))
|
||||
.setSmallIcon(android.R.drawable.ic_menu_help)
|
||||
.setAutoCancel(true)
|
||||
.setDefaults(Notification.DEFAULT_SOUND)
|
||||
.setDefaults(Notification.DEFAULT_ALL)
|
||||
.build();
|
||||
|
||||
|
||||
@@ -452,13 +452,19 @@ public class Device implements BaseLink.PackageReceiver {
|
||||
}
|
||||
} else if (!isPaired()) {
|
||||
|
||||
//TODO: Notify the other side that we don't trust them
|
||||
unpair();
|
||||
Log.e("onPackageReceived","Device not paired, ignoring package!");
|
||||
|
||||
} else {
|
||||
|
||||
for (Plugin plugin : plugins.values()) {
|
||||
plugin.onPackageReceived(np);
|
||||
try {
|
||||
plugin.onPackageReceived(np);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
Log.e("Device", "Exception in "+plugin.getDisplayName()+"'s onPackageReceived()");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -491,13 +497,19 @@ public class Device implements BaseLink.PackageReceiver {
|
||||
ArrayList<BaseLink> mLinks = new ArrayList<BaseLink>(links);
|
||||
|
||||
boolean success = false;
|
||||
for(BaseLink link : mLinks) {
|
||||
if (useEncryption) {
|
||||
success = link.sendPackageEncrypted(np, publicKey);
|
||||
} else {
|
||||
success = link.sendPackage(np);
|
||||
try {
|
||||
for (BaseLink link : mLinks) {
|
||||
if (useEncryption) {
|
||||
success = link.sendPackageEncrypted(np, publicKey);
|
||||
} else {
|
||||
success = link.sendPackage(np);
|
||||
}
|
||||
if (success) break;
|
||||
}
|
||||
if (success) break;
|
||||
} catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
Log.e("sendPackage","Error while sending package");
|
||||
success = false;
|
||||
}
|
||||
|
||||
if (success) {
|
||||
@@ -529,7 +541,7 @@ public class Device implements BaseLink.PackageReceiver {
|
||||
return plugins.get(name);
|
||||
}
|
||||
|
||||
private void addPlugin(final String name) {
|
||||
private synchronized void addPlugin(final String name) {
|
||||
Plugin existing = plugins.get(name);
|
||||
if (existing != null) {
|
||||
Log.w("addPlugin","plugin already present:" + name);
|
||||
@@ -547,24 +559,25 @@ public class Device implements BaseLink.PackageReceiver {
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
boolean success;
|
||||
try {
|
||||
boolean success = plugin.onCreate();
|
||||
if (!success) {
|
||||
Log.e("addPlugin", "plugin failed to load " + name);
|
||||
failedPlugins.put(name, plugin);
|
||||
return;
|
||||
}
|
||||
success = plugin.onCreate();
|
||||
} catch (Exception e) {
|
||||
failedPlugins.put(name, plugin);
|
||||
success = false;
|
||||
e.printStackTrace();
|
||||
Log.e("addPlugin", "Exception loading plugin " + name);
|
||||
return;
|
||||
}
|
||||
|
||||
//Log.e("addPlugin","added " + name);
|
||||
|
||||
failedPlugins.remove(name);
|
||||
plugins.put(name, plugin);
|
||||
if (success) {
|
||||
//Log.e("addPlugin","added " + name);
|
||||
failedPlugins.remove(name);
|
||||
plugins.put(name, plugin);
|
||||
} else {
|
||||
Log.e("addPlugin", "plugin failed to load " + name);
|
||||
plugins.remove(name);
|
||||
failedPlugins.put(name, plugin);
|
||||
}
|
||||
|
||||
for (PluginsChangedListener listener : pluginsChangedListeners) {
|
||||
listener.onPluginsChanged(Device.this);
|
||||
@@ -575,13 +588,14 @@ public class Device implements BaseLink.PackageReceiver {
|
||||
|
||||
}
|
||||
|
||||
private boolean removePlugin(String name) {
|
||||
private synchronized boolean removePlugin(String name) {
|
||||
|
||||
Plugin plugin = plugins.remove(name);
|
||||
Plugin failedPlugin = failedPlugins.remove(name);
|
||||
|
||||
if (plugin == null) {
|
||||
if (failedPlugin == null) {
|
||||
//Not found
|
||||
return false;
|
||||
}
|
||||
plugin = failedPlugin;
|
||||
@@ -589,25 +603,22 @@ public class Device implements BaseLink.PackageReceiver {
|
||||
|
||||
try {
|
||||
plugin.onDestroy();
|
||||
//Log.e("removePlugin","removed " + name);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
Log.e("removePlugin","Exception calling onDestroy for plugin "+name);
|
||||
return false;
|
||||
}
|
||||
|
||||
//Log.e("removePlugin","removed " + name);
|
||||
|
||||
for (PluginsChangedListener listener : pluginsChangedListeners) {
|
||||
listener.onPluginsChanged(this);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
public void setPluginEnabled(String pluginName, boolean value) {
|
||||
settings.edit().putBoolean(pluginName,value).commit();
|
||||
if (value) addPlugin(pluginName);
|
||||
if (value && isPaired() && isReachable()) addPlugin(pluginName);
|
||||
else removePlugin(pluginName);
|
||||
}
|
||||
|
||||
@@ -617,6 +628,9 @@ public class Device implements BaseLink.PackageReceiver {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
public boolean hasPluginsLoaded() {
|
||||
return !plugins.isEmpty() || !failedPlugins.isEmpty();
|
||||
}
|
||||
|
||||
public void reloadPluginsFromSettings() {
|
||||
|
||||
@@ -636,9 +650,7 @@ public class Device implements BaseLink.PackageReceiver {
|
||||
}
|
||||
}
|
||||
|
||||
for (PluginsChangedListener listener : pluginsChangedListeners) {
|
||||
listener.onPluginsChanged(this);
|
||||
}
|
||||
//No need to call PluginsChangedListeners because addPlugin and removePlugin already do so
|
||||
}
|
||||
|
||||
public HashMap<String,Plugin> getLoadedPlugins() {
|
||||
@@ -653,7 +665,7 @@ public class Device implements BaseLink.PackageReceiver {
|
||||
void onPluginsChanged(Device device);
|
||||
}
|
||||
|
||||
private ArrayList<PluginsChangedListener> pluginsChangedListeners = new ArrayList<PluginsChangedListener>();
|
||||
private final ArrayList<PluginsChangedListener> pluginsChangedListeners = new ArrayList<PluginsChangedListener>();
|
||||
|
||||
public void addPluginsChangedListener(PluginsChangedListener listener) {
|
||||
pluginsChangedListeners.add(listener);
|
||||
|
@@ -13,7 +13,7 @@ public class AppsHelper {
|
||||
try {
|
||||
|
||||
PackageManager pm = context.getPackageManager();
|
||||
ApplicationInfo ai = pm.getApplicationInfo( packageName, 0);
|
||||
ApplicationInfo ai = pm.getApplicationInfo(packageName, 0);
|
||||
|
||||
return pm.getApplicationLabel(ai).toString();
|
||||
|
||||
|
@@ -3,9 +3,7 @@ package org.kde.kdeconnect.Helpers;
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.provider.ContactsContract;
|
||||
import android.provider.ContactsContract.PhoneLookup;
|
||||
import android.util.Log;
|
||||
|
||||
public class ContactsHelper {
|
||||
|
||||
@@ -31,12 +29,12 @@ public class ContactsHelper {
|
||||
|
||||
// Take the first match only
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
int nameIndex = cursor.getColumnIndex(ContactsContract.PhoneLookup.DISPLAY_NAME);
|
||||
int nameIndex = cursor.getColumnIndex(PhoneLookup.DISPLAY_NAME);
|
||||
if (nameIndex != -1) {
|
||||
String name = cursor.getString(nameIndex);
|
||||
//Log.e("PhoneNumberLookup", "success: " + name);
|
||||
cursor.close();
|
||||
return name;
|
||||
return name + " (" + number + ")";
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -11,7 +11,7 @@ public class DeviceHelper {
|
||||
//from https://github.com/meetup/android-device-names
|
||||
//Converted to java using:
|
||||
//cat android_models.properties | awk -F'=' '{sub(/ *$/, "", $1)} sub(/^ */, "", $2) { if ($2 != "") print "humanReadableNames.put(\""$1"\",\"" $2 "\");"}'
|
||||
private static HashMap<String,String> humanReadableNames = new HashMap<String,String>();
|
||||
private final static HashMap<String,String> humanReadableNames = new HashMap<String,String>();
|
||||
static {
|
||||
humanReadableNames.put("5860E","Coolpad Quattro 4G");
|
||||
humanReadableNames.put("ADR6300","HTC Droid Incredible");
|
||||
@@ -24,6 +24,9 @@ public class DeviceHelper {
|
||||
humanReadableNames.put("C5155","Kyocera Rise");
|
||||
humanReadableNames.put("C5170","Kyocera Hydro");
|
||||
humanReadableNames.put("C6603","Sony Xperia Z");
|
||||
humanReadableNames.put("C6606","Sony Xperia Z");
|
||||
humanReadableNames.put("C6903","Sony Xperia Z1");
|
||||
humanReadableNames.put("D6503","Sony Xperia Z2");
|
||||
humanReadableNames.put("Desire_HD","HTC Desire HD");
|
||||
humanReadableNames.put("DROID2_GLOBAL","Motorola Droid 2 Global");
|
||||
humanReadableNames.put("DROID2","Motorola Droid 2");
|
||||
@@ -40,34 +43,45 @@ public class DeviceHelper {
|
||||
humanReadableNames.put("Galaxy_Nexus","Samsung Galaxy Nexus");
|
||||
humanReadableNames.put("google_sdk","Android Emulator");
|
||||
humanReadableNames.put("GT-I8160","Samsung Galaxy Ace 2");
|
||||
humanReadableNames.put("GT-I8190N","Samsung Galaxy S III Mini");
|
||||
humanReadableNames.put("GT-I8190","Samsung Galaxy S III Mini");
|
||||
humanReadableNames.put("GT-I9000","Samsung Galaxy S");
|
||||
humanReadableNames.put("GT-I9001","Samsung Galaxy S Plus");
|
||||
humanReadableNames.put("GT-I9070","Samsung Galaxy S Advance");
|
||||
humanReadableNames.put("GT-I9082","Samsung Galaxy Grand");
|
||||
humanReadableNames.put("GT-I9100M","Samsung Galaxy S II");
|
||||
humanReadableNames.put("GT-I9100P","Samsung Galaxy S II");
|
||||
humanReadableNames.put("GT-I9100","Samsung Galaxy S II");
|
||||
humanReadableNames.put("GT-I9100T","Samsung Galaxy S II");
|
||||
humanReadableNames.put("GT-I9195","Samsung Galaxy S4 Mini");
|
||||
humanReadableNames.put("GT-I9300","Samsung Galaxy S III");
|
||||
humanReadableNames.put("GT-I9300T","Samsung Galaxy S III");
|
||||
humanReadableNames.put("GT-I9305","Samsung Galaxy S III");
|
||||
humanReadableNames.put("GT-I9505","Samsung Galaxy S 4");
|
||||
humanReadableNames.put("GT-I9305T","Samsung Galaxy S III");
|
||||
humanReadableNames.put("GT-I9500","Samsung Galaxy S4");
|
||||
humanReadableNames.put("GT-I9505","Samsung Galaxy S4");
|
||||
humanReadableNames.put("GT-N5110","Samsung Galaxy Note 8.0");
|
||||
humanReadableNames.put("GT-N7000","Samsung Galaxy Note");
|
||||
humanReadableNames.put("GT-N7100","Samsung Galaxy Note II");
|
||||
humanReadableNames.put("GT-N7105","Samsung Galaxy Note II");
|
||||
humanReadableNames.put("GT-N8013","Samsung Galaxy Note 10.1");
|
||||
humanReadableNames.put("GT-P3113","Samsung Galaxy Tab 2 7.0");
|
||||
humanReadableNames.put("GT-P5113","Samsnung Galaxy Tab 2 10.1");
|
||||
humanReadableNames.put("GT-P5210","Samsung Galaxy Tab 3 10.1");
|
||||
humanReadableNames.put("GT-P7510","Samsung Galaxy Tab 10.1");
|
||||
humanReadableNames.put("GT-S5360","Samsung Galaxy Y");
|
||||
humanReadableNames.put("GT-S5570","Samsung Galaxy Mini");
|
||||
humanReadableNames.put("GT-S5830i","Samsung Galaxy Ace");
|
||||
humanReadableNames.put("GT-S5830","Samsung Galaxy Ace");
|
||||
humanReadableNames.put("GT-S7562","Samsung Galaxy S Duos");
|
||||
humanReadableNames.put("HTC6435LVW","HTC Droid DNA");
|
||||
humanReadableNames.put("HTC6500LVW","HTC One");
|
||||
humanReadableNames.put("HTC_Desire_HD_A9191","HTC Desire HD");
|
||||
humanReadableNames.put("HTCEVODesign4G","HTC Evo Design 4G");
|
||||
humanReadableNames.put("HTCEVOV4G","HTC Evo V 4G");
|
||||
humanReadableNames.put("HTCONE","HTC One");
|
||||
humanReadableNames.put("HTC_PH39100","HTC Vivid 4G");
|
||||
humanReadableNames.put("HTC_PN071","HTC One");
|
||||
humanReadableNames.put("HTC_Sensation_Z710e","HTC Sensation");
|
||||
humanReadableNames.put("HTC_VLE_U","HTC One S");
|
||||
humanReadableNames.put("KFJWA","Kindle Fire HD 8.9");
|
||||
@@ -75,9 +89,17 @@ public class DeviceHelper {
|
||||
humanReadableNames.put("KFOT","Kindle Fire");
|
||||
humanReadableNames.put("KFTT","Kindle Fire HD 7");
|
||||
humanReadableNames.put("LG-C800","LG myTouch Q");
|
||||
humanReadableNames.put("LG-D800","LG G2");
|
||||
humanReadableNames.put("LG-D801","LG G2");
|
||||
humanReadableNames.put("LG-D802","LG G2");
|
||||
humanReadableNames.put("LG-E739","LG MyTouch e739");
|
||||
humanReadableNames.put("LG-E970","LG Optimus G");
|
||||
humanReadableNames.put("LG-E980","LG Optimus G Pro");
|
||||
humanReadableNames.put("LGL55C","LG LGL55C");
|
||||
humanReadableNames.put("LG-LS840","LG Viper");
|
||||
humanReadableNames.put("LG-LS970","LG Optimus G");
|
||||
humanReadableNames.put("LG-LS980","LG G2");
|
||||
humanReadableNames.put("LGMS769","LG Optimus L9");
|
||||
humanReadableNames.put("LG-MS770","LG Motion 4G");
|
||||
humanReadableNames.put("LG-MS910","LG Esteem");
|
||||
humanReadableNames.put("LG-P509","LG Optimus T");
|
||||
@@ -93,18 +115,20 @@ public class DeviceHelper {
|
||||
humanReadableNames.put("MOTWX435KT","Motorola Triumph");
|
||||
humanReadableNames.put("myTouch_4G_Slide","HTC myTouch 4G Slide");
|
||||
humanReadableNames.put("N860","ZTE Warp N860");
|
||||
humanReadableNames.put("Nexus_10","Google Nexus 10");
|
||||
humanReadableNames.put("Nexus_4","Google Nexus 4");
|
||||
humanReadableNames.put("Nexus_7","Asus Nexus 7");
|
||||
humanReadableNames.put("Nexus_S_4G","Samsung Nexus S 4G");
|
||||
humanReadableNames.put("Nexus_S","Samsung Nexus S");
|
||||
humanReadableNames.put("Nexus_10","Nexus 10");
|
||||
humanReadableNames.put("Nexus_4","Nexus 4");
|
||||
humanReadableNames.put("Nexus_5","Nexus 5");
|
||||
humanReadableNames.put("Nexus_7","Nexus 7");
|
||||
humanReadableNames.put("Nexus_S_4G","Nexus S 4G");
|
||||
humanReadableNames.put("Nexus_S","Nexus S");
|
||||
humanReadableNames.put("PantechP9070","Pantech Burst");
|
||||
humanReadableNames.put("PC36100","HTC Evo 4G");
|
||||
humanReadableNames.put("PG06100","HTC EVO Shift 4G");
|
||||
humanReadableNames.put("PG86100","HTC Evo 3D");
|
||||
humanReadableNames.put("PH44100","HTC Evo Design 4G");
|
||||
humanReadableNames.put("SAMSUNG-SGH-I317","Samsung Galaxy Note II");
|
||||
humanReadableNames.put("SAMSUNG-SGH-I337","Samsung Galaxy S 4");
|
||||
humanReadableNames.put("SAMSUNG-SGH-I337","Samsung Galaxy S4");
|
||||
humanReadableNames.put("SAMSUNG-SGH-I537","Samsung Galaxy S4 Active");
|
||||
humanReadableNames.put("SAMSUNG-SGH-I717","Samsung Galaxy Note");
|
||||
humanReadableNames.put("SAMSUNG-SGH-I727","Samsung Skyrocket");
|
||||
humanReadableNames.put("SAMSUNG-SGH-I747","Samsung Galaxy S III");
|
||||
@@ -112,22 +136,27 @@ public class DeviceHelper {
|
||||
humanReadableNames.put("SAMSUNG-SGH-I897","Samsung Captivate");
|
||||
humanReadableNames.put("SAMSUNG-SGH-I927","Samsung Captivate Glide");
|
||||
humanReadableNames.put("SAMSUNG-SGH-I997","Samsung Infuse 4G");
|
||||
humanReadableNames.put("SAMSUNG-SM-N900A","Samsung Galaxy Note 3");
|
||||
humanReadableNames.put("SCH-I200","Samsung Galaxy Stellar");
|
||||
humanReadableNames.put("SCH-I405","Samsung Stratosphere");
|
||||
humanReadableNames.put("SCH-I415","Samsung Galaxy Stratosphere II");
|
||||
humanReadableNames.put("SCH-I500","Samsung Fascinate");
|
||||
humanReadableNames.put("SCH-I510","Samsung Droid Charge");
|
||||
humanReadableNames.put("SCH-I535","Samsung Galaxy S III");
|
||||
humanReadableNames.put("SCH-I545","Samsung Galaxy S 4");
|
||||
humanReadableNames.put("SCH-I545","Samsung Galaxy S4");
|
||||
humanReadableNames.put("SCH-I605","Samsung Galaxy Note II");
|
||||
humanReadableNames.put("SCH-I800","Samsung Galaxy Tab 7.0");
|
||||
humanReadableNames.put("SCH-R530M","Samsung Galaxy S III");
|
||||
humanReadableNames.put("SCH-R530U","Samsung Galaxy S III");
|
||||
humanReadableNames.put("SCH-R720","Samsung Admire");
|
||||
humanReadableNames.put("SCH-S720C","Samsung Proclaim");
|
||||
humanReadableNames.put("SCH-S738C","Samsung Galaxy Centura");
|
||||
humanReadableNames.put("SGH-I317M","Samsung Galaxy Note II");
|
||||
humanReadableNames.put("SGH-I337M","Samsung Galaxy S4");
|
||||
humanReadableNames.put("SGH-I727R","Samsung Galaxy S II");
|
||||
humanReadableNames.put("SGH-I747M","Samsung Galaxy S III");
|
||||
humanReadableNames.put("SGH-M919","Samsung Galaxy S 4");
|
||||
humanReadableNames.put("SGH-M919","Samsung Galaxy S4");
|
||||
humanReadableNames.put("SGH-T599N","Samsung Galaxy Exhibit");
|
||||
humanReadableNames.put("SGH-T679","Samsung Exhibit II");
|
||||
humanReadableNames.put("SGH-T769","Samsung Galaxy S Blaze");
|
||||
humanReadableNames.put("SGH-T889","Samsung Galaxy Note II");
|
||||
@@ -135,24 +164,44 @@ public class DeviceHelper {
|
||||
humanReadableNames.put("SGH-T959V","Samsung Galaxy S 4G");
|
||||
humanReadableNames.put("SGH-T989D","Samsung Galaxy S II");
|
||||
humanReadableNames.put("SGH-T989","Samsung Galaxy S II");
|
||||
humanReadableNames.put("SGH-T999L","Samsung Galaxy S III");
|
||||
humanReadableNames.put("SGH-T999","Samsung Galaxy S III");
|
||||
humanReadableNames.put("SGH-T999V","Samsung Galaxy S III");
|
||||
humanReadableNames.put("SHV-E210S","Samsung Galaxy S III");
|
||||
humanReadableNames.put("SM-N9005","Samsung Galaxy Note 3");
|
||||
humanReadableNames.put("SM-N900P","Samsung Galaxy Note 3");
|
||||
humanReadableNames.put("SM-N900T","Samsung Galaxy Note 3");
|
||||
humanReadableNames.put("SM-N900V","Samsung Galaxy Note 3");
|
||||
humanReadableNames.put("SM-N900W8","Samsung Galaxy Note 3");
|
||||
humanReadableNames.put("SM-T210R","Samsung Galaxy Tab 3 7.0");
|
||||
humanReadableNames.put("SM-T310","Samsung Galaxy Tab 3 8.0");
|
||||
humanReadableNames.put("SPH-D600","Samsung Conquer 4G");
|
||||
humanReadableNames.put("SPH-D700","Samsung Epic 4G");
|
||||
humanReadableNames.put("SPH-D710BST","Samsung Galaxy S II");
|
||||
humanReadableNames.put("SPH-D710","Samsung Epic");
|
||||
humanReadableNames.put("SPH-D710VMUB","Samsung Galaxy S II");
|
||||
humanReadableNames.put("SPH-L300","Samsung Galaxy Victory");
|
||||
humanReadableNames.put("SPH-L710","Samsung Galaxy S III");
|
||||
humanReadableNames.put("SPH-L720","Samsung Galaxy S 4");
|
||||
humanReadableNames.put("SPH-L720","Samsung Galaxy S4");
|
||||
humanReadableNames.put("SPH-L900","Samsung Galaxy Note II");
|
||||
humanReadableNames.put("SPH-M820-BST","Samsung Galaxy Prevail");
|
||||
humanReadableNames.put("SPH-M830","Samsung Galaxy Rush");
|
||||
humanReadableNames.put("SPH-M930BST","Samsung Transform Ultra");
|
||||
humanReadableNames.put("ST25i","Sony Xperia U");
|
||||
humanReadableNames.put("Transformer_Prime_TF201","Asus Eee Pad Transformer Prime");
|
||||
humanReadableNames.put("Transformer_TF101","Asus Eee Pad Transformer");
|
||||
humanReadableNames.put("VM670","LG Optimus V");
|
||||
humanReadableNames.put("VS840_4G","LG Lucid 4G");
|
||||
humanReadableNames.put("VS910_4G","LG Revolution 4G");
|
||||
humanReadableNames.put("VS920_4G","LG Spectrum 4G");
|
||||
humanReadableNames.put("VS980_4G","LG G2");
|
||||
humanReadableNames.put("Xoom","Motorola Xoom");
|
||||
humanReadableNames.put("XT1030","Motorola Droid Mini");
|
||||
humanReadableNames.put("XT1032","Motorola Moto G");
|
||||
humanReadableNames.put("XT1058","Motorola Moto X");
|
||||
humanReadableNames.put("XT1060","Motorola Moto X");
|
||||
humanReadableNames.put("XT1080","Motorola Droid Ultra");
|
||||
humanReadableNames.put("XT897","Motorola Photo Q");
|
||||
humanReadableNames.put("XT907","Motorola Droid Razr M");
|
||||
}
|
||||
|
||||
|
56
src/main/java/org/kde/kdeconnect/Helpers/FilesHelper.java
Normal file
@@ -0,0 +1,56 @@
|
||||
package org.kde.kdeconnect.Helpers;
|
||||
|
||||
import android.webkit.MimeTypeMap;
|
||||
|
||||
public class FilesHelper {
|
||||
|
||||
public static String getFileExt(String fileName) {
|
||||
//return MimeTypeMap.getFileExtensionFromUrl(fileName);
|
||||
return fileName.substring((fileName.lastIndexOf(".") + 1), fileName.length());
|
||||
}
|
||||
|
||||
public static String getMimeTypeFromFile(String file) {
|
||||
String mime = MimeTypeMap.getSingleton().getMimeTypeFromExtension(getFileExt(file));
|
||||
if (mime == null) mime = "*/*";
|
||||
return mime;
|
||||
}
|
||||
|
||||
//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.
|
||||
* The result will only include ascii characters and numbers, and the "-","_", and "." characters.
|
||||
*
|
||||
* @param name
|
||||
* @param dirSeparators
|
||||
* @param maxFileLength
|
||||
* @return
|
||||
*/
|
||||
public static String toFileSystemSafeName(String name, boolean dirSeparators, int maxFileLength) {
|
||||
int size = name.length();
|
||||
StringBuilder rc = new StringBuilder(size * 2);
|
||||
for (int i = 0; i < size; i++) {
|
||||
char c = name.charAt(i);
|
||||
boolean valid = c >= 'a' && c <= 'z';
|
||||
valid = valid || (c >= 'A' && c <= 'Z');
|
||||
valid = valid || (c >= '0' && c <= '9');
|
||||
valid = valid || (c == '_') || (c == '-') || (c == '.');
|
||||
valid = valid || (dirSeparators && ( (c == '/') || (c == '\\')));
|
||||
|
||||
if (valid) {
|
||||
rc.append(c);
|
||||
}
|
||||
}
|
||||
String result = rc.toString();
|
||||
if (result.length() > maxFileLength) {
|
||||
result = result.substring(result.length()-maxFileLength,result.length());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
public static String toFileSystemSafeName(String name, boolean dirSeparators) {
|
||||
return toFileSystemSafeName(name, dirSeparators, 255);
|
||||
}
|
||||
public static String toFileSystemSafeName(String name) {
|
||||
return toFileSystemSafeName(name, true, 255);
|
||||
}
|
||||
|
||||
}
|
101
src/main/java/org/kde/kdeconnect/Helpers/StorageHelper.java
Normal file
@@ -0,0 +1,101 @@
|
||||
package org.kde.kdeconnect.Helpers;
|
||||
|
||||
import android.os.Environment;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
//Code from http://stackoverflow.com/questions/9340332/how-can-i-get-the-list-of-mounted-external-storage-of-android-device/19982338#19982338
|
||||
public class StorageHelper {
|
||||
|
||||
private static final String TAG = "StorageHelper";
|
||||
|
||||
public static class StorageInfo {
|
||||
|
||||
public final String path;
|
||||
public final boolean readonly;
|
||||
public final boolean removable;
|
||||
public final int number;
|
||||
|
||||
StorageInfo(String path, boolean readonly, boolean removable, int number) {
|
||||
this.path = path;
|
||||
this.readonly = readonly;
|
||||
this.removable = removable;
|
||||
this.number = number;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static List<StorageInfo> getStorageList() {
|
||||
|
||||
List<StorageInfo> list = new ArrayList<StorageInfo>();
|
||||
String def_path = Environment.getExternalStorageDirectory().getPath();
|
||||
boolean def_path_removable = Environment.isExternalStorageRemovable();
|
||||
String def_path_state = Environment.getExternalStorageState();
|
||||
boolean def_path_available = def_path_state.equals(Environment.MEDIA_MOUNTED)
|
||||
|| def_path_state.equals(Environment.MEDIA_MOUNTED_READ_ONLY);
|
||||
boolean def_path_readonly = Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED_READ_ONLY);
|
||||
|
||||
HashSet<String> paths = new HashSet<String>();
|
||||
int cur_removable_number = 1;
|
||||
|
||||
if (def_path_available) {
|
||||
paths.add(def_path);
|
||||
list.add(0, new StorageInfo(def_path, def_path_readonly, def_path_removable, def_path_removable ? cur_removable_number++ : -1));
|
||||
}
|
||||
|
||||
BufferedReader buf_reader = null;
|
||||
try {
|
||||
buf_reader = new BufferedReader(new FileReader("/proc/mounts"));
|
||||
String line;
|
||||
Log.d(TAG, "/proc/mounts");
|
||||
while ((line = buf_reader.readLine()) != null) {
|
||||
Log.d(TAG, line);
|
||||
if (line.contains("vfat") || line.contains("/mnt")) {
|
||||
StringTokenizer tokens = new StringTokenizer(line, " ");
|
||||
String unused = tokens.nextToken(); //device
|
||||
String mount_point = tokens.nextToken(); //mount point
|
||||
if (paths.contains(mount_point)) {
|
||||
continue;
|
||||
}
|
||||
unused = tokens.nextToken(); //file system
|
||||
List<String> flags = Arrays.asList(tokens.nextToken().split(",")); //flags
|
||||
boolean readonly = flags.contains("ro");
|
||||
|
||||
if (line.contains("/dev/block/vold")) {
|
||||
if (!line.contains("/mnt/secure")
|
||||
&& !line.contains("/mnt/asec")
|
||||
&& !line.contains("/mnt/obb")
|
||||
&& !line.contains("/dev/mapper")
|
||||
&& !line.contains("tmpfs")) {
|
||||
paths.add(mount_point);
|
||||
list.add(new StorageInfo(mount_point, readonly, true, cur_removable_number++));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} catch (FileNotFoundException ex) {
|
||||
ex.printStackTrace();
|
||||
} catch (IOException ex) {
|
||||
ex.printStackTrace();
|
||||
} finally {
|
||||
if (buf_reader != null) {
|
||||
try {
|
||||
buf_reader.close();
|
||||
} catch (IOException ex) {}
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
}
|
@@ -8,7 +8,6 @@ import android.util.Base64;
|
||||
import android.util.Log;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import org.kde.kdeconnect.Helpers.DeviceHelper;
|
||||
import org.kde.kdeconnect.UserInterface.MainSettingsActivity;
|
||||
@@ -33,9 +32,11 @@ public class NetworkPackage {
|
||||
public final static String PACKAGE_TYPE_PING = "kdeconnect.ping";
|
||||
public final static String PACKAGE_TYPE_TELEPHONY = "kdeconnect.telephony";
|
||||
public final static String PACKAGE_TYPE_BATTERY = "kdeconnect.battery";
|
||||
public final static String PACKAGE_TYPE_SFTP = "kdeconnect.sftp";
|
||||
public final static String PACKAGE_TYPE_NOTIFICATION = "kdeconnect.notification";
|
||||
public final static String PACKAGE_TYPE_CLIPBOARD = "kdeconnect.clipboard";
|
||||
public final static String PACKAGE_TYPE_MPRIS = "kdeconnect.mpris";
|
||||
public final static String PACKAGE_TYPE_MOUSEPAD = "kdeconnect.mousepad";
|
||||
public final static String PACKAGE_TYPE_SHARE = "kdeconnect.share";
|
||||
|
||||
private long mId;
|
||||
|
@@ -8,7 +8,6 @@ import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.BatteryManager;
|
||||
import android.util.Log;
|
||||
import android.widget.Button;
|
||||
|
||||
import org.kde.kdeconnect.NetworkPackage;
|
||||
@@ -17,13 +16,11 @@ import org.kde.kdeconnect_tp.R;
|
||||
|
||||
public class BatteryPlugin extends Plugin {
|
||||
|
||||
private NetworkPackage lastPackage = null;
|
||||
// keep these fields in sync with kdeconnect-kded:BatteryPlugin.h:ThresholdBatteryEvent
|
||||
private static final int THRESHOLD_EVENT_NONE= 0;
|
||||
private static final int THRESHOLD_EVENT_BATTERY_LOW = 1;
|
||||
|
||||
private IntentFilter filter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
|
||||
|
||||
/*static {
|
||||
PluginFactory.registerPlugin(BatteryPlugin.class);
|
||||
}*/
|
||||
private NetworkPackage lastInfo = null;
|
||||
|
||||
@Override
|
||||
public String getPluginName() {
|
||||
@@ -45,41 +42,46 @@ public class BatteryPlugin extends Plugin {
|
||||
return context.getResources().getDrawable(R.drawable.icon);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasSettings() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabledByDefault() {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
private BroadcastReceiver receiver = new BroadcastReceiver() {
|
||||
private final BroadcastReceiver receiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
public void onReceive(Context context, Intent batteryIntent) {
|
||||
|
||||
Log.i("BatteryPlugin", "Battery event");
|
||||
Intent batteryChargeIntent = context.registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
|
||||
int level = batteryChargeIntent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
|
||||
int scale = batteryChargeIntent.getIntExtra(BatteryManager.EXTRA_SCALE, 1);
|
||||
int currentCharge = level*100 / scale;
|
||||
boolean isCharging = (0 != batteryChargeIntent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0));
|
||||
boolean lowBattery = Intent.ACTION_BATTERY_LOW.equals(batteryIntent.getAction());
|
||||
int thresholdEvent = lowBattery? THRESHOLD_EVENT_BATTERY_LOW : THRESHOLD_EVENT_NONE;
|
||||
|
||||
boolean isCharging = (0 != intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0));
|
||||
|
||||
int currentCharge = 100;
|
||||
int status = intent.getIntExtra(BatteryManager.EXTRA_STATUS, -1);
|
||||
if (status != BatteryManager.BATTERY_STATUS_FULL) {
|
||||
Intent batteryStatus = context.registerReceiver(null, filter);
|
||||
int level = batteryStatus.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
|
||||
int scale = batteryStatus.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
|
||||
currentCharge = level*100 / scale;
|
||||
}
|
||||
|
||||
//Only notify if change is meaningful enough
|
||||
if (lastPackage == null
|
||||
|| (
|
||||
isCharging != lastPackage.getBoolean("isCharging")
|
||||
|| currentCharge != lastPackage.getInt("currentCharge")
|
||||
)
|
||||
if (lastInfo != null
|
||||
&& isCharging != lastInfo.getBoolean("isCharging")
|
||||
&& currentCharge != lastInfo.getInt("currentCharge")
|
||||
&& thresholdEvent != lastInfo.getInt("thresholdEvent")
|
||||
) {
|
||||
|
||||
//Do not send again if nothing has changed
|
||||
return;
|
||||
|
||||
} else {
|
||||
|
||||
NetworkPackage np = new NetworkPackage(NetworkPackage.PACKAGE_TYPE_BATTERY);
|
||||
np.set("isCharging", isCharging);
|
||||
np.set("currentCharge", currentCharge);
|
||||
np.set("isCharging", isCharging);
|
||||
np.set("thresholdEvent", thresholdEvent);
|
||||
device.sendPackage(np);
|
||||
lastPackage = np;
|
||||
lastInfo = np;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -87,12 +89,14 @@ public class BatteryPlugin extends Plugin {
|
||||
|
||||
@Override
|
||||
public boolean onCreate() {
|
||||
context.registerReceiver(receiver, filter);
|
||||
context.registerReceiver(receiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
|
||||
context.registerReceiver(receiver, new IntentFilter(Intent.ACTION_BATTERY_LOW));
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
//It's okay to call this only once, even though we registered it for two filters
|
||||
context.unregisterReceiver(receiver);
|
||||
}
|
||||
|
||||
@@ -101,8 +105,8 @@ public class BatteryPlugin extends Plugin {
|
||||
if (!np.getType().equals(NetworkPackage.PACKAGE_TYPE_BATTERY)) return false;
|
||||
|
||||
if (np.getBoolean("request")) {
|
||||
if (lastPackage != null) {
|
||||
device.sendPackage(lastPackage);
|
||||
if (lastInfo != null) {
|
||||
device.sendPackage(lastInfo);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -110,7 +114,7 @@ public class BatteryPlugin extends Plugin {
|
||||
}
|
||||
|
||||
@Override
|
||||
public AlertDialog getErrorDialog(Context baseContext) {
|
||||
public AlertDialog getErrorDialog(Activity deviceActivity) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@@ -10,12 +10,18 @@ import org.kde.kdeconnect.NetworkPackage;
|
||||
public class ClipboardListener {
|
||||
|
||||
|
||||
private final Context context;
|
||||
private String currentContent;
|
||||
|
||||
private ClipboardManager cm = null;
|
||||
ClipboardManager.OnPrimaryClipChangedListener listener;
|
||||
private ClipboardManager.OnPrimaryClipChangedListener listener;
|
||||
|
||||
ClipboardListener(final Context ctx, final Device device) {
|
||||
context = ctx;
|
||||
if(android.os.Build.VERSION.SDK_INT < 11) {
|
||||
return;
|
||||
}
|
||||
|
||||
ClipboardListener(final Context context, final Device device) {
|
||||
cm = (ClipboardManager)context.getSystemService(Context.CLIPBOARD_SERVICE);
|
||||
listener = new ClipboardManager.OnPrimaryClipChangedListener() {
|
||||
@Override
|
||||
@@ -41,12 +47,24 @@ public class ClipboardListener {
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
if(android.os.Build.VERSION.SDK_INT < 11) {
|
||||
return;
|
||||
}
|
||||
|
||||
cm.removePrimaryClipChangedListener(listener);
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public void setText(String text) {
|
||||
currentContent = text;
|
||||
cm.setText(text);
|
||||
if(android.os.Build.VERSION.SDK_INT < 11) {
|
||||
android.text.ClipboardManager clipboard = (android.text.ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
|
||||
clipboard.setText(text);
|
||||
}
|
||||
else
|
||||
{
|
||||
cm.setText(text);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -3,9 +3,7 @@ package org.kde.kdeconnect.Plugins.ClibpoardPlugin;
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Build;
|
||||
import android.widget.Button;
|
||||
|
||||
import org.kde.kdeconnect.NetworkPackage;
|
||||
@@ -14,10 +12,6 @@ import org.kde.kdeconnect_tp.R;
|
||||
|
||||
public class ClipboardPlugin extends Plugin {
|
||||
|
||||
/*static {
|
||||
PluginFactory.registerPlugin(ClipboardPlugin.class);
|
||||
}*/
|
||||
|
||||
@Override
|
||||
public String getPluginName() {
|
||||
return "plugin_clipboard";
|
||||
@@ -37,33 +31,28 @@ public class ClipboardPlugin extends Plugin {
|
||||
return context.getResources().getDrawable(R.drawable.icon);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasSettings() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabledByDefault() {
|
||||
return (Build.VERSION.SDK_INT >= 11);
|
||||
//Disabled by default due to just one direction sync(incoming clipboard change) in early version of android.
|
||||
return (android.os.Build.VERSION.SDK_INT >= 11);
|
||||
}
|
||||
|
||||
private ClipboardListener listener;
|
||||
|
||||
@Override
|
||||
public boolean onCreate() {
|
||||
|
||||
if (Build.VERSION.SDK_INT < 11) {
|
||||
return false;
|
||||
}
|
||||
|
||||
listener = new ClipboardListener(context, device);
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
|
||||
if (Build.VERSION.SDK_INT < 11) return;
|
||||
|
||||
listener.stop();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -76,22 +65,10 @@ public class ClipboardPlugin extends Plugin {
|
||||
String content = np.getString("content");
|
||||
listener.setText(content);
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public AlertDialog getErrorDialog(Context baseContext) {
|
||||
return new AlertDialog.Builder(baseContext)
|
||||
.setTitle(R.string.pref_plugin_clipboard)
|
||||
.setMessage(R.string.plugin_not_available)
|
||||
.setPositiveButton("Ok",new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialogInterface, int i) {
|
||||
|
||||
}
|
||||
})
|
||||
.create();
|
||||
}
|
||||
public AlertDialog getErrorDialog(Activity deviceActivity) { return null; }
|
||||
|
||||
@Override
|
||||
public Button getInterfaceButton(Activity activity) {
|
||||
|
@@ -0,0 +1,103 @@
|
||||
package org.kde.kdeconnect.Plugins.MousePadPlugin;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Build;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.View;
|
||||
import android.view.inputmethod.EditorInfo;
|
||||
import android.view.inputmethod.InputConnection;
|
||||
|
||||
import org.kde.kdeconnect.BackgroundService;
|
||||
import org.kde.kdeconnect.Device;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.HashMap;
|
||||
|
||||
public class KeyListenerView extends View {
|
||||
|
||||
private String deviceId;
|
||||
|
||||
private static HashMap<Integer, Integer> SpecialKeysMap = new HashMap<Integer, Integer>();
|
||||
static {
|
||||
int i = 0;
|
||||
SpecialKeysMap.put(KeyEvent.KEYCODE_DEL, ++i); // 1
|
||||
SpecialKeysMap.put(KeyEvent.KEYCODE_TAB, ++i); // 2
|
||||
SpecialKeysMap.put(KeyEvent.KEYCODE_ENTER, 12); ++i; // 3 is not used, return is 12 instead
|
||||
SpecialKeysMap.put(KeyEvent.KEYCODE_DPAD_LEFT, ++i); // 4
|
||||
SpecialKeysMap.put(KeyEvent.KEYCODE_DPAD_UP, ++i); // 5
|
||||
SpecialKeysMap.put(KeyEvent.KEYCODE_DPAD_RIGHT, ++i); // 6
|
||||
SpecialKeysMap.put(KeyEvent.KEYCODE_DPAD_DOWN, ++i); // 7
|
||||
SpecialKeysMap.put(KeyEvent.KEYCODE_PAGE_UP, ++i); // 8
|
||||
SpecialKeysMap.put(KeyEvent.KEYCODE_PAGE_DOWN, ++i); // 9
|
||||
if (Build.VERSION.SDK_INT >= 11) {
|
||||
SpecialKeysMap.put(KeyEvent.KEYCODE_MOVE_HOME, ++i); // 10
|
||||
SpecialKeysMap.put(KeyEvent.KEYCODE_MOVE_END, ++i); // 11
|
||||
SpecialKeysMap.put(KeyEvent.KEYCODE_NUMPAD_ENTER, ++i); // 12
|
||||
SpecialKeysMap.put(KeyEvent.KEYCODE_FORWARD_DEL, ++i); // 13
|
||||
SpecialKeysMap.put(KeyEvent.KEYCODE_ESCAPE, ++i); // 14
|
||||
}
|
||||
}
|
||||
|
||||
public void setDeviceId(String id) {
|
||||
deviceId = id;
|
||||
}
|
||||
|
||||
public KeyListenerView(Context context, AttributeSet set) {
|
||||
super(context, set);
|
||||
|
||||
setFocusable(true);
|
||||
setFocusableInTouchMode(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
|
||||
outAttrs.imeOptions = EditorInfo.IME_FLAG_NO_FULLSCREEN;
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCheckIsTextEditor() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onKeyUp(int keyCode, KeyEvent event) {
|
||||
|
||||
char utfChar = (char)event.getUnicodeChar();
|
||||
if (utfChar == 9 || utfChar == 10) utfChar = 0; //Workaround to send enter and tab as special keys instead of characters
|
||||
|
||||
if (utfChar != 0) {
|
||||
final String utfString = new String(new char[]{utfChar});
|
||||
BackgroundService.RunCommand(getContext(), new BackgroundService.InstanceCallback() {
|
||||
@Override
|
||||
public void onServiceStart(BackgroundService service) {
|
||||
Device device = service.getDevice(deviceId);
|
||||
MousePadPlugin mousePadPlugin = (MousePadPlugin)device.getPlugin("plugin_mousepad");
|
||||
if (mousePadPlugin == null) return;
|
||||
|
||||
mousePadPlugin.sendKey(utfString);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
if (!SpecialKeysMap.containsKey(keyCode)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final int specialKey = SpecialKeysMap.get(keyCode);
|
||||
BackgroundService.RunCommand(getContext(), new BackgroundService.InstanceCallback() {
|
||||
@Override
|
||||
public void onServiceStart(BackgroundService service) {
|
||||
Device device = service.getDevice(deviceId);
|
||||
MousePadPlugin mousePadPlugin = (MousePadPlugin)device.getPlugin("plugin_mousepad");
|
||||
if (mousePadPlugin == null) return;
|
||||
mousePadPlugin.sendSpecialKey(specialKey);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,254 @@
|
||||
package org.kde.kdeconnect.Plugins.MousePadPlugin;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.support.v7.app.ActionBarActivity;
|
||||
import android.view.GestureDetector;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.MotionEvent;
|
||||
|
||||
import org.kde.kdeconnect.BackgroundService;
|
||||
import org.kde.kdeconnect.Device;
|
||||
import org.kde.kdeconnect_tp.R;
|
||||
|
||||
public class MousePadActivity extends ActionBarActivity implements GestureDetector.OnGestureListener, GestureDetector.OnDoubleTapListener, MousePadGestureDetector.OnGestureListener {
|
||||
|
||||
String deviceId;
|
||||
|
||||
private final static float MinDistanceToSendScroll = 2.5f;
|
||||
|
||||
private float mPrevX;
|
||||
private float mPrevY;
|
||||
private float mCurrentX;
|
||||
private float mCurrentY;
|
||||
|
||||
boolean isScrolling = false;
|
||||
float accumulatedDistanceY = 0;
|
||||
|
||||
private GestureDetector mDetector;
|
||||
private MousePadGestureDetector mMousePadGestureDetector;
|
||||
|
||||
KeyListenerView keyListenerView;
|
||||
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
setContentView(R.layout.activity_mousepad);
|
||||
|
||||
deviceId = getIntent().getStringExtra("deviceId");
|
||||
|
||||
mDetector = new GestureDetector(this, this);
|
||||
mMousePadGestureDetector = new MousePadGestureDetector(this, this);
|
||||
mDetector.setOnDoubleTapListener(this);
|
||||
|
||||
keyListenerView = (KeyListenerView)findViewById(R.id.keyListener);
|
||||
keyListenerView.setDeviceId(deviceId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
MenuInflater inflater = getMenuInflater();
|
||||
inflater.inflate(R.menu.menu_mousepad, menu);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case R.id.menu_right_click:
|
||||
sendRightClick();
|
||||
return true;
|
||||
case R.id.menu_middle_click:
|
||||
sendMiddleClick();
|
||||
return true;
|
||||
case R.id.menu_show_keyboard:
|
||||
showKeyboard();
|
||||
return true;
|
||||
default:
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent event) {
|
||||
if (mMousePadGestureDetector.onTouchEvent(event)) {
|
||||
return true;
|
||||
}
|
||||
if ( mDetector.onTouchEvent(event) ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
int actionType = event.getAction();
|
||||
|
||||
if (isScrolling) {
|
||||
if (actionType == MotionEvent.ACTION_UP) {
|
||||
isScrolling = false;
|
||||
} else {
|
||||
return false;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
switch (actionType) {
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
mPrevX = event.getX();
|
||||
mPrevY = event.getY();
|
||||
break;
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
mCurrentX = event.getX();
|
||||
mCurrentY = event.getY();
|
||||
BackgroundService.RunCommand(this, new BackgroundService.InstanceCallback() {
|
||||
@Override
|
||||
public void onServiceStart(BackgroundService service) {
|
||||
Device device = service.getDevice(deviceId);
|
||||
MousePadPlugin mousePadPlugin = (MousePadPlugin)device.getPlugin("plugin_mousepad");
|
||||
if (mousePadPlugin == null) return;
|
||||
mousePadPlugin.sendMouseDelta(mCurrentX - mPrevX, mCurrentY - mPrevY);
|
||||
mPrevX = mCurrentX;
|
||||
mPrevY = mCurrentY;
|
||||
}
|
||||
});
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onDown(MotionEvent e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onShowPress(MotionEvent e) {
|
||||
//From GestureDetector, left empty
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onSingleTapUp(MotionEvent e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onScroll(MotionEvent e1, MotionEvent e2, final float distanceX, final float distanceY) {
|
||||
// If only one thumb is used then cancel the scroll gesture
|
||||
if (e2.getPointerCount() <= 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
isScrolling = true;
|
||||
|
||||
accumulatedDistanceY += distanceY;
|
||||
if (accumulatedDistanceY > MinDistanceToSendScroll || accumulatedDistanceY < -MinDistanceToSendScroll)
|
||||
{
|
||||
final float scrollToSendY = accumulatedDistanceY;
|
||||
|
||||
BackgroundService.RunCommand(this, new BackgroundService.InstanceCallback() {
|
||||
@Override
|
||||
public void onServiceStart(BackgroundService service) {
|
||||
Device device = service.getDevice(deviceId);
|
||||
MousePadPlugin mousePadPlugin = (MousePadPlugin)device.getPlugin("plugin_mousepad");
|
||||
if (mousePadPlugin == null) return;
|
||||
mousePadPlugin.sendScroll(0, scrollToSendY);
|
||||
}
|
||||
});
|
||||
|
||||
accumulatedDistanceY = 0;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLongPress(MotionEvent e) {
|
||||
//From GestureDetector, left empty
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onSingleTapConfirmed(MotionEvent e) {
|
||||
BackgroundService.RunCommand(this, new BackgroundService.InstanceCallback() {
|
||||
@Override
|
||||
public void onServiceStart(BackgroundService service) {
|
||||
Device device = service.getDevice(deviceId);
|
||||
MousePadPlugin mousePadPlugin = (MousePadPlugin)device.getPlugin("plugin_mousepad");
|
||||
if (mousePadPlugin == null) return;
|
||||
mousePadPlugin.sendSingleClick();
|
||||
}
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onDoubleTap(MotionEvent e) {
|
||||
BackgroundService.RunCommand(this, new BackgroundService.InstanceCallback() {
|
||||
@Override
|
||||
public void onServiceStart(BackgroundService service) {
|
||||
Device device = service.getDevice(deviceId);
|
||||
MousePadPlugin mousePadPlugin = (MousePadPlugin)device.getPlugin("plugin_mousepad");
|
||||
if (mousePadPlugin == null) return;
|
||||
mousePadPlugin.sendDoubleClick();
|
||||
}
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onDoubleTapEvent(MotionEvent e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTripleFingerTap(MotionEvent ev) {
|
||||
sendMiddleClick();
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onDoubleFingerTap(MotionEvent ev) {
|
||||
sendRightClick();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
private void sendMiddleClick() {
|
||||
BackgroundService.RunCommand(this, new BackgroundService.InstanceCallback() {
|
||||
@Override
|
||||
public void onServiceStart(BackgroundService service) {
|
||||
Device device = service.getDevice(deviceId);
|
||||
MousePadPlugin mousePadPlugin = (MousePadPlugin)device.getPlugin("plugin_mousepad");
|
||||
if (mousePadPlugin == null) return;
|
||||
mousePadPlugin.sendMiddleClick();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void sendRightClick() {
|
||||
BackgroundService.RunCommand(this, new BackgroundService.InstanceCallback() {
|
||||
@Override
|
||||
public void onServiceStart(BackgroundService service) {
|
||||
Device device = service.getDevice(deviceId);
|
||||
MousePadPlugin mousePadPlugin = (MousePadPlugin)device.getPlugin("plugin_mousepad");
|
||||
if (mousePadPlugin == null) return;
|
||||
mousePadPlugin.sendRightClick();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void showKeyboard() {
|
||||
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
|
||||
imm.toggleSoftInputFromWindow(keyListenerView.getWindowToken(), 0, 0);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -0,0 +1,59 @@
|
||||
package org.kde.kdeconnect.Plugins.MousePadPlugin;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.ViewConfiguration;
|
||||
|
||||
|
||||
public class MousePadGestureDetector {
|
||||
|
||||
private static final int TAP_TIMEOUT = ViewConfiguration.getTapTimeout() + 100;
|
||||
private OnGestureListener mGestureListener;
|
||||
|
||||
private Context mCtx;
|
||||
|
||||
private long mFirstDownTime = 0;
|
||||
|
||||
private boolean mIsGestureHandled;
|
||||
|
||||
public interface OnGestureListener {
|
||||
|
||||
boolean onTripleFingerTap(MotionEvent ev);
|
||||
|
||||
boolean onDoubleFingerTap(MotionEvent ev);
|
||||
}
|
||||
|
||||
public MousePadGestureDetector(Context ctx, OnGestureListener gestureListener) {
|
||||
if (gestureListener == null) {
|
||||
throw new IllegalArgumentException("gestureListener cannot be null");
|
||||
}
|
||||
mGestureListener = gestureListener;
|
||||
mCtx = ctx;
|
||||
}
|
||||
|
||||
public boolean onTouchEvent(MotionEvent event) {
|
||||
int action = event.getAction();
|
||||
switch (action & MotionEvent.ACTION_MASK) {
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
mIsGestureHandled = false;
|
||||
mFirstDownTime = event.getEventTime();
|
||||
break;
|
||||
case MotionEvent.ACTION_POINTER_UP:
|
||||
int count = event.getPointerCount();
|
||||
if (event.getEventTime() - mFirstDownTime <= TAP_TIMEOUT) {
|
||||
if (count == 3) {
|
||||
if (!mIsGestureHandled) {
|
||||
mIsGestureHandled = mGestureListener.onTripleFingerTap(event);
|
||||
}
|
||||
} else if (count == 2) {
|
||||
if (!mIsGestureHandled) {
|
||||
mIsGestureHandled = mGestureListener.onDoubleFingerTap(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
mFirstDownTime = 0;
|
||||
break;
|
||||
}
|
||||
return mIsGestureHandled;
|
||||
}
|
||||
}
|
@@ -0,0 +1,131 @@
|
||||
package org.kde.kdeconnect.Plugins.MousePadPlugin;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.view.View;
|
||||
import android.widget.Button;
|
||||
|
||||
import org.kde.kdeconnect.NetworkPackage;
|
||||
import org.kde.kdeconnect.Plugins.Plugin;
|
||||
import org.kde.kdeconnect_tp.R;
|
||||
|
||||
public class MousePadPlugin extends Plugin {
|
||||
|
||||
@Override
|
||||
public String getPluginName() {
|
||||
return "plugin_mousepad";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayName() {
|
||||
return context.getString(R.string.pref_plugin_mousepad);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return context.getString(R.string.pref_plugin_mousepad_desc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Drawable getIcon() {
|
||||
return context.getResources().getDrawable(R.drawable.icon);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabledByDefault() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasSettings() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreate() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPackageReceived(NetworkPackage np) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AlertDialog getErrorDialog(Activity deviceActivity) { return null; }
|
||||
|
||||
@Override
|
||||
public Button getInterfaceButton(final Activity activity) {
|
||||
Button button = new Button(activity);
|
||||
button.setText(R.string.open_mousepad);
|
||||
button.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
Intent intent = new Intent(activity, MousePadActivity.class);
|
||||
intent.putExtra("deviceId", device.getDeviceId());
|
||||
activity.startActivity(intent);
|
||||
}
|
||||
});
|
||||
return button;
|
||||
}
|
||||
|
||||
public void sendMouseDelta(float dx, float dy) {
|
||||
NetworkPackage np = new NetworkPackage(NetworkPackage.PACKAGE_TYPE_MOUSEPAD);
|
||||
np.set("dx", dx);
|
||||
np.set("dy", dy);
|
||||
device.sendPackage(np);
|
||||
}
|
||||
|
||||
public void sendSingleClick() {
|
||||
NetworkPackage np = new NetworkPackage(NetworkPackage.PACKAGE_TYPE_MOUSEPAD);
|
||||
np.set("singleclick", true);
|
||||
device.sendPackage(np);
|
||||
}
|
||||
|
||||
public void sendDoubleClick() {
|
||||
NetworkPackage np = new NetworkPackage(NetworkPackage.PACKAGE_TYPE_MOUSEPAD);
|
||||
np.set("doubleclick", true);
|
||||
device.sendPackage(np);
|
||||
}
|
||||
|
||||
public void sendMiddleClick() {
|
||||
NetworkPackage np = new NetworkPackage(NetworkPackage.PACKAGE_TYPE_MOUSEPAD);
|
||||
np.set("middleclick", true);
|
||||
device.sendPackage(np);
|
||||
}
|
||||
|
||||
public void sendRightClick() {
|
||||
NetworkPackage np = new NetworkPackage(NetworkPackage.PACKAGE_TYPE_MOUSEPAD);
|
||||
np.set("rightclick", true);
|
||||
device.sendPackage(np);
|
||||
}
|
||||
|
||||
public void sendScroll(float dx, float dy) {
|
||||
NetworkPackage np = new NetworkPackage(NetworkPackage.PACKAGE_TYPE_MOUSEPAD);
|
||||
np.set("scroll", true);
|
||||
np.set("dx", dx);
|
||||
np.set("dy", dy);
|
||||
device.sendPackage(np);
|
||||
}
|
||||
|
||||
public void sendKey(String utfChar) {
|
||||
NetworkPackage np = new NetworkPackage(NetworkPackage.PACKAGE_TYPE_MOUSEPAD);
|
||||
np.set("key", utfChar);
|
||||
device.sendPackage(np);
|
||||
}
|
||||
|
||||
public void sendSpecialKey(int specialKey) {
|
||||
NetworkPackage np = new NetworkPackage(NetworkPackage.PACKAGE_TYPE_MOUSEPAD);
|
||||
np.set("specialKey", specialKey);
|
||||
device.sendPackage(np);
|
||||
}
|
||||
|
||||
}
|
@@ -1,10 +1,13 @@
|
||||
package org.kde.kdeconnect.Plugins.MprisPlugin;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Message;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.util.Log;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.View;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.ArrayAdapter;
|
||||
@@ -24,9 +27,11 @@ import java.util.ArrayList;
|
||||
|
||||
public class MprisActivity extends Activity {
|
||||
|
||||
//TODO: Add a loading spinner at the begginning (to distinguish the loading state from a no-players state).
|
||||
//TODO: Add a loading spinner at the beginning (to distinguish the loading state from a no-players state).
|
||||
//TODO 2: Add a message when no players are detected after loading completes
|
||||
|
||||
private String deviceId;
|
||||
|
||||
protected void connectToPlugin() {
|
||||
|
||||
final String deviceId = getIntent().getStringExtra("deviceId");
|
||||
@@ -67,8 +72,6 @@ public class MprisActivity extends Activity {
|
||||
});
|
||||
|
||||
mpris.setPlayerListUpdatedHandler(new Handler() {
|
||||
boolean firstLoad = true;
|
||||
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
final ArrayList<String> playerList = mpris.getPlayerList();
|
||||
@@ -104,17 +107,18 @@ public class MprisActivity extends Activity {
|
||||
|
||||
@Override
|
||||
public void onNothingSelected(AdapterView<?> arg0) {
|
||||
|
||||
mpris.setPlayer(null);
|
||||
}
|
||||
});
|
||||
|
||||
// restore the selected player
|
||||
int position = adapter.getPosition(mpris.getPlayer());
|
||||
|
||||
if (position >= 0) {
|
||||
spinner.setSelection(position);
|
||||
}
|
||||
}
|
||||
});
|
||||
if (firstLoad) {
|
||||
firstLoad = false;
|
||||
if (playerList.size() > 0) {
|
||||
mpris.setPlayer(playerList.get(0));
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -123,7 +127,7 @@ public class MprisActivity extends Activity {
|
||||
|
||||
}
|
||||
|
||||
BaseLinkProvider.ConnectionReceiver connectionReceiver = new BaseLinkProvider.ConnectionReceiver() {
|
||||
private final BaseLinkProvider.ConnectionReceiver connectionReceiver = new BaseLinkProvider.ConnectionReceiver() {
|
||||
@Override
|
||||
public void onConnectionReceived(NetworkPackage identityPackage, BaseLink link) {
|
||||
connectToPlugin();
|
||||
@@ -146,12 +150,78 @@ public class MprisActivity extends Activity {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Change current volume with provided step.
|
||||
*
|
||||
* @param mpris multimedia controller
|
||||
* @param step step size volume change
|
||||
*/
|
||||
private void updateVolume(MprisPlugin mpris, int step) {
|
||||
final int currentVolume = mpris.getVolume();
|
||||
if(currentVolume < 100 || currentVolume > 0) {
|
||||
int newVolume = currentVolume + step;
|
||||
if(newVolume > 100) {
|
||||
newVolume = 100;
|
||||
} else if (newVolume <0 ) {
|
||||
newVolume = 0;
|
||||
}
|
||||
mpris.setVolume(newVolume);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onKeyDown(int keyCode, KeyEvent event) {
|
||||
switch (keyCode) {
|
||||
case KeyEvent.KEYCODE_VOLUME_UP:
|
||||
BackgroundService.RunCommand(MprisActivity.this, new BackgroundService.InstanceCallback() {
|
||||
@Override
|
||||
public void onServiceStart(BackgroundService service) {
|
||||
Device device = service.getDevice(deviceId);
|
||||
MprisPlugin mpris = (MprisPlugin) device.getPlugin("plugin_mpris");
|
||||
if (mpris == null) return;
|
||||
updateVolume(mpris, 5);
|
||||
}
|
||||
});
|
||||
return true;
|
||||
case KeyEvent.KEYCODE_VOLUME_DOWN:
|
||||
BackgroundService.RunCommand(MprisActivity.this, new BackgroundService.InstanceCallback() {
|
||||
@Override
|
||||
public void onServiceStart(BackgroundService service) {
|
||||
Device device = service.getDevice(deviceId);
|
||||
MprisPlugin mpris = (MprisPlugin) device.getPlugin("plugin_mpris");
|
||||
if (mpris == null) return;
|
||||
updateVolume(mpris, -5);
|
||||
}
|
||||
});
|
||||
return true;
|
||||
default:
|
||||
return super.onKeyDown(keyCode, event);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onKeyUp(int keyCode, KeyEvent event) {
|
||||
switch (keyCode) {
|
||||
case KeyEvent.KEYCODE_VOLUME_UP:
|
||||
return true;
|
||||
case KeyEvent.KEYCODE_VOLUME_DOWN:
|
||||
return true;
|
||||
default:
|
||||
return super.onKeyUp(keyCode, event);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.mpris_control);
|
||||
|
||||
final String deviceId = getIntent().getStringExtra("deviceId");
|
||||
deviceId = getIntent().getStringExtra("deviceId");
|
||||
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
String interval_time_str = prefs.getString(getString(R.string.mpris_time_key),
|
||||
getString(R.string.mpris_time_default));
|
||||
final int interval_time = Integer.parseInt(interval_time_str);
|
||||
|
||||
BackgroundService.RunCommand(MprisActivity.this, new BackgroundService.InstanceCallback() {
|
||||
@Override
|
||||
@@ -200,7 +270,7 @@ public class MprisActivity extends Activity {
|
||||
Device device = service.getDevice(deviceId);
|
||||
MprisPlugin mpris = (MprisPlugin)device.getPlugin("plugin_mpris");
|
||||
if (mpris == null) return;
|
||||
mpris.Seek(-10000000); // -10 seconds. TODO: plugin settings UI?
|
||||
mpris.Seek(interval_time * -1);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -215,7 +285,7 @@ public class MprisActivity extends Activity {
|
||||
Device device = service.getDevice(deviceId);
|
||||
MprisPlugin mpris = (MprisPlugin)device.getPlugin("plugin_mpris");
|
||||
if (mpris == null) return;
|
||||
mpris.Seek(10000000); // 10 seconds. TODO: plugin settings UI?
|
||||
mpris.Seek(interval_time);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -238,10 +308,12 @@ public class MprisActivity extends Activity {
|
||||
|
||||
((SeekBar)findViewById(R.id.volume_seek)).setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
|
||||
@Override
|
||||
public void onProgressChanged(SeekBar seekBar, int i, boolean b) { }
|
||||
public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStartTrackingTouch(SeekBar seekBar) { }
|
||||
public void onStartTrackingTouch(SeekBar seekBar) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStopTrackingTouch(final SeekBar seekBar) {
|
||||
@@ -253,12 +325,14 @@ public class MprisActivity extends Activity {
|
||||
if (mpris == null) return;
|
||||
mpris.setVolume(seekBar.getProgress());
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -30,10 +30,6 @@ public class MprisPlugin extends Plugin {
|
||||
private String player = "";
|
||||
private boolean playing = false;
|
||||
|
||||
/*static {
|
||||
PluginFactory.registerPlugin(MprisPlugin.class);
|
||||
}*/
|
||||
|
||||
@Override
|
||||
public String getPluginName() {
|
||||
return "plugin_mpris";
|
||||
@@ -54,6 +50,11 @@ public class MprisPlugin extends Plugin {
|
||||
return context.getResources().getDrawable(R.drawable.icon);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasSettings() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabledByDefault() {
|
||||
return true;
|
||||
@@ -179,6 +180,10 @@ public class MprisPlugin extends Plugin {
|
||||
requestPlayerStatus();
|
||||
}
|
||||
|
||||
public String getPlayer() {
|
||||
return player;
|
||||
}
|
||||
|
||||
public int getVolume() {
|
||||
return volume;
|
||||
}
|
||||
@@ -203,7 +208,7 @@ public class MprisPlugin extends Plugin {
|
||||
}
|
||||
|
||||
@Override
|
||||
public AlertDialog getErrorDialog(Context baseContext) {
|
||||
public AlertDialog getErrorDialog(Activity deviceActivity) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@@ -5,7 +5,6 @@ import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.service.notification.NotificationListenerService;
|
||||
import android.service.notification.StatusBarNotification;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
@@ -16,7 +15,7 @@ public class NotificationReceiver extends NotificationListenerService {
|
||||
void onNotificationRemoved(StatusBarNotification statusBarNotification);
|
||||
}
|
||||
|
||||
private ArrayList<NotificationListener> listeners = new ArrayList<NotificationListener>();
|
||||
private final ArrayList<NotificationListener> listeners = new ArrayList<NotificationListener>();
|
||||
|
||||
public void addListener(NotificationListener listener) {
|
||||
listeners.add(listener);
|
||||
@@ -61,7 +60,7 @@ public class NotificationReceiver extends NotificationListenerService {
|
||||
void onServiceStart(NotificationReceiver service);
|
||||
}
|
||||
|
||||
private static ArrayList<InstanceCallback> callbacks = new ArrayList<InstanceCallback>();
|
||||
private final static ArrayList<InstanceCallback> callbacks = new ArrayList<InstanceCallback>();
|
||||
|
||||
public static void Start(Context c) {
|
||||
RunCommand(c, null);
|
||||
|
@@ -6,31 +6,22 @@ import android.app.Notification;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.provider.Settings;
|
||||
import android.service.notification.StatusBarNotification;
|
||||
import android.util.Base64;
|
||||
import android.util.Log;
|
||||
import android.widget.Button;
|
||||
|
||||
import org.kde.kdeconnect.Helpers.AppsHelper;
|
||||
import org.kde.kdeconnect.Helpers.ImagesHelper;
|
||||
import org.kde.kdeconnect.NetworkPackage;
|
||||
import org.kde.kdeconnect.Plugins.Plugin;
|
||||
import org.kde.kdeconnect.UserInterface.DeviceActivity;
|
||||
import org.kde.kdeconnect_tp.R;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
public class NotificationsPlugin extends Plugin implements NotificationReceiver.NotificationListener {
|
||||
|
||||
/*static {
|
||||
PluginFactory.registerPlugin(NotificationsPlugin.class);
|
||||
}*/
|
||||
|
||||
@Override
|
||||
public String getPluginName() {
|
||||
return "plugin_notifications";
|
||||
@@ -51,6 +42,11 @@ public class NotificationsPlugin extends Plugin implements NotificationReceiver.
|
||||
return context.getResources().getDrawable(R.drawable.icon);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasSettings() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabledByDefault() {
|
||||
return true;
|
||||
@@ -116,7 +112,9 @@ public class NotificationsPlugin extends Plugin implements NotificationReceiver.
|
||||
@Override
|
||||
public boolean onCreate() {
|
||||
|
||||
if (Build.VERSION.SDK_INT < 18) return false;
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//Check for permissions
|
||||
String notificationListenerList = Settings.Secure.getString(context.getContentResolver(), "enabled_notification_listeners");
|
||||
@@ -128,7 +126,7 @@ public class NotificationsPlugin extends Plugin implements NotificationReceiver.
|
||||
service.addListener(NotificationsPlugin.this);
|
||||
StatusBarNotification[] notifications = service.getActiveNotifications();
|
||||
for (StatusBarNotification notification : notifications) {
|
||||
onNotificationPosted(notification);
|
||||
sendNotification(notification, true);
|
||||
}
|
||||
} catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
@@ -146,6 +144,11 @@ public class NotificationsPlugin extends Plugin implements NotificationReceiver.
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2) {
|
||||
return;
|
||||
}
|
||||
|
||||
NotificationReceiver.RunCommand(context, new NotificationReceiver.InstanceCallback() {
|
||||
@Override
|
||||
public void onServiceStart(NotificationReceiver service) {
|
||||
@@ -176,6 +179,13 @@ public class NotificationsPlugin extends Plugin implements NotificationReceiver.
|
||||
public void sendNotification(StatusBarNotification statusBarNotification, boolean requestAnswer) {
|
||||
|
||||
Notification notification = statusBarNotification.getNotification();
|
||||
|
||||
if ((notification.flags & Notification.FLAG_FOREGROUND_SERVICE) != 0
|
||||
|| (notification.flags & Notification.FLAG_ONGOING_EVENT) != 0 ) {
|
||||
//This is not a notification!
|
||||
return;
|
||||
}
|
||||
|
||||
NotificationId id = NotificationId.fromNotification(statusBarNotification);
|
||||
|
||||
NetworkPackage np = new NetworkPackage(NetworkPackage.PACKAGE_TYPE_NOTIFICATION);
|
||||
@@ -202,7 +212,7 @@ public class NotificationsPlugin extends Plugin implements NotificationReceiver.
|
||||
np.set("id", id.serialize());
|
||||
np.set("appName", appName == null? packageName : appName);
|
||||
np.set("isClearable", statusBarNotification.isClearable());
|
||||
np.set("ticker", (notification != null && notification.tickerText != null)? notification.tickerText.toString() : "");
|
||||
np.set("ticker", getTickerText(notification));
|
||||
np.set("time", Long.toString(statusBarNotification.getPostTime()));
|
||||
if (requestAnswer) np.set("requestAnswer", true);
|
||||
|
||||
@@ -210,7 +220,43 @@ public class NotificationsPlugin extends Plugin implements NotificationReceiver.
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the ticker text of the notification.
|
||||
* If device android version is KitKat or newer, the title and text of the notification is used
|
||||
* instead the ticker text.
|
||||
*/
|
||||
private String getTickerText(Notification notification) {
|
||||
final String TITLE_KEY = "android.title";
|
||||
final String TEXT_KEY = "android.text";
|
||||
String ticker = "";
|
||||
|
||||
if(notification != null) {
|
||||
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
try {
|
||||
Bundle extras = notification.extras;
|
||||
String extraTitle = extras.getString(TITLE_KEY);
|
||||
String extraText = extras.getString(TEXT_KEY);
|
||||
|
||||
if (extraTitle != null && extraText != null) {
|
||||
ticker = extraTitle + " ‐ " + extraText;
|
||||
} else if (extraTitle != null) {
|
||||
ticker = extraTitle;
|
||||
} else if (extraText != null) {
|
||||
ticker = extraText;
|
||||
}
|
||||
} catch(Exception e) {
|
||||
Log.w("NotificationPlugin","problem parsing notification extras");
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
if (ticker.isEmpty()) {
|
||||
ticker = (notification.tickerText != null)? notification.tickerText.toString() : "";
|
||||
}
|
||||
}
|
||||
|
||||
return ticker;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@@ -274,10 +320,10 @@ public class NotificationsPlugin extends Plugin implements NotificationReceiver.
|
||||
|
||||
|
||||
@Override
|
||||
public AlertDialog getErrorDialog(final Context baseContext) {
|
||||
public AlertDialog getErrorDialog(final Activity deviceActivity) {
|
||||
|
||||
if (Build.VERSION.SDK_INT < 18) {
|
||||
return new AlertDialog.Builder(baseContext)
|
||||
return new AlertDialog.Builder(deviceActivity)
|
||||
.setTitle(R.string.pref_plugin_notifications)
|
||||
.setMessage(R.string.plugin_not_available)
|
||||
.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
|
||||
@@ -288,14 +334,14 @@ public class NotificationsPlugin extends Plugin implements NotificationReceiver.
|
||||
})
|
||||
.create();
|
||||
} else {
|
||||
return new AlertDialog.Builder(baseContext)
|
||||
return new AlertDialog.Builder(deviceActivity)
|
||||
.setTitle(R.string.pref_plugin_notifications)
|
||||
.setMessage(R.string.no_permissions)
|
||||
.setPositiveButton(R.string.open_settings, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialogInterface, int i) {
|
||||
Intent intent = new Intent("android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS");
|
||||
baseContext.startActivity(intent);
|
||||
deviceActivity.startActivityForResult(intent, DeviceActivity.RESULT_NEEDS_RELOAD);
|
||||
}
|
||||
})
|
||||
.setNegativeButton(R.string.cancel,new DialogInterface.OnClickListener() {
|
||||
|
@@ -4,23 +4,23 @@ import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.support.v4.app.NotificationCompat;
|
||||
import android.support.v4.app.TaskStackBuilder;
|
||||
import android.view.View;
|
||||
import android.widget.Button;
|
||||
|
||||
import org.kde.kdeconnect.NetworkPackage;
|
||||
import org.kde.kdeconnect.Plugins.Plugin;
|
||||
import org.kde.kdeconnect.UserInterface.MainActivity;
|
||||
import org.kde.kdeconnect_tp.R;
|
||||
|
||||
|
||||
public class PingPlugin extends Plugin {
|
||||
|
||||
/*static {
|
||||
PluginFactory.registerPlugin(PingPlugin.class);
|
||||
}*/
|
||||
|
||||
@Override
|
||||
public String getPluginName() {
|
||||
return "plugin_ping";
|
||||
@@ -41,6 +41,11 @@ public class PingPlugin extends Plugin {
|
||||
return context.getResources().getDrawable(R.drawable.icon);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasSettings() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabledByDefault() {
|
||||
return true;
|
||||
@@ -63,17 +68,36 @@ public class PingPlugin extends Plugin {
|
||||
if (np.getType().equals(NetworkPackage.PACKAGE_TYPE_PING)) {
|
||||
//Log.e("PingPackageReceiver", "was a ping!");
|
||||
|
||||
TaskStackBuilder stackBuilder = TaskStackBuilder.create(context);
|
||||
stackBuilder.addParentStack(MainActivity.class);
|
||||
stackBuilder.addNextIntent(new Intent(context, MainActivity.class));
|
||||
PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(
|
||||
0,
|
||||
PendingIntent.FLAG_UPDATE_CURRENT
|
||||
);
|
||||
|
||||
int id;
|
||||
String message;
|
||||
if (np.has("message")) {
|
||||
message = np.getString("message");
|
||||
id = (int)System.currentTimeMillis();
|
||||
} else {
|
||||
message = "Ping!";
|
||||
id = 42; //A unique id to create only one notification
|
||||
}
|
||||
|
||||
Notification noti = new NotificationCompat.Builder(context)
|
||||
.setContentTitle(device.getName())
|
||||
.setContentText("Ping!")
|
||||
.setTicker("Ping!")
|
||||
.setContentText(message)
|
||||
.setContentIntent(resultPendingIntent)
|
||||
.setTicker(message)
|
||||
.setSmallIcon(android.R.drawable.ic_dialog_alert)
|
||||
.setAutoCancel(true)
|
||||
.setDefaults(Notification.DEFAULT_SOUND)
|
||||
.setDefaults(Notification.DEFAULT_ALL)
|
||||
.build();
|
||||
|
||||
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
notificationManager.notify(42 /*a unique id to create only one notification*/, noti);
|
||||
notificationManager.notify(id, noti);
|
||||
return true;
|
||||
|
||||
}
|
||||
@@ -81,7 +105,7 @@ public class PingPlugin extends Plugin {
|
||||
}
|
||||
|
||||
@Override
|
||||
public AlertDialog getErrorDialog(Context baseContext) {
|
||||
public AlertDialog getErrorDialog(Activity deviceActivity) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@@ -51,6 +51,12 @@ public abstract class Plugin {
|
||||
*/
|
||||
public abstract boolean isEnabledByDefault();
|
||||
|
||||
|
||||
/**
|
||||
* Return true if this plugin needs an specific UI settings.
|
||||
*/
|
||||
public abstract boolean hasSettings();
|
||||
|
||||
/**
|
||||
* Initialize the listeners and structures in your plugin.
|
||||
* Should return true if initialization was successful.
|
||||
@@ -73,7 +79,7 @@ public abstract class Plugin {
|
||||
* If onCreate returns false, should create a dialog explaining
|
||||
* the problem (and how to fix it, if possible) to the user.
|
||||
*/
|
||||
public abstract AlertDialog getErrorDialog(Context baseContext);
|
||||
public abstract AlertDialog getErrorDialog(Activity deviceActivity);
|
||||
|
||||
/**
|
||||
* Creates a button that will be displayed in the user interface
|
||||
|
@@ -7,10 +7,13 @@ import android.util.Log;
|
||||
|
||||
import org.kde.kdeconnect.Device;
|
||||
import org.kde.kdeconnect.Plugins.BatteryPlugin.BatteryPlugin;
|
||||
import org.kde.kdeconnect.Plugins.MousePadPlugin.MousePadPlugin;
|
||||
import org.kde.kdeconnect.Plugins.SftpPlugin.SftpPlugin;
|
||||
import org.kde.kdeconnect.Plugins.ClibpoardPlugin.ClipboardPlugin;
|
||||
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.SharePlugin.SharePlugin;
|
||||
import org.kde.kdeconnect.Plugins.TelephonyPlugin.TelephonyPlugin;
|
||||
|
||||
import java.util.Map;
|
||||
@@ -21,12 +24,14 @@ public class PluginFactory {
|
||||
|
||||
public static class PluginInfo {
|
||||
|
||||
public PluginInfo(String pluginName, String displayName, String description, Drawable icon, boolean enabledByDefault) {
|
||||
public PluginInfo(String pluginName, String displayName, String description, Drawable icon,
|
||||
boolean enabledByDefault, boolean hasSettings) {
|
||||
this.pluginName = pluginName;
|
||||
this.displayName = displayName;
|
||||
this.description = description;
|
||||
this.icon = icon;
|
||||
this.enabledByDefault = enabledByDefault;
|
||||
this.hasSettings = hasSettings;
|
||||
}
|
||||
|
||||
public String getPluginName() {
|
||||
@@ -45,15 +50,18 @@ public class PluginFactory {
|
||||
return icon;
|
||||
}
|
||||
|
||||
public boolean hasSettings() { return hasSettings; }
|
||||
|
||||
public boolean isEnabledByDefault() {
|
||||
return enabledByDefault;
|
||||
}
|
||||
|
||||
private String pluginName;
|
||||
private String displayName;
|
||||
private String description;
|
||||
private final String pluginName;
|
||||
private final String displayName;
|
||||
private final String description;
|
||||
private final Drawable icon;
|
||||
private boolean enabledByDefault;
|
||||
private final boolean enabledByDefault;
|
||||
private final boolean hasSettings;
|
||||
|
||||
}
|
||||
|
||||
@@ -61,13 +69,16 @@ public class PluginFactory {
|
||||
private static final Map<String, PluginInfo> availablePluginsInfo = new TreeMap<String, PluginInfo>();
|
||||
|
||||
static {
|
||||
//TODO: Avoid this factory having to know every plugin
|
||||
//TODO: Use reflection to find all subclasses of Plugin, instead of adding them manually
|
||||
PluginFactory.registerPlugin(TelephonyPlugin.class);
|
||||
PluginFactory.registerPlugin(PingPlugin.class);
|
||||
PluginFactory.registerPlugin(MprisPlugin.class);
|
||||
PluginFactory.registerPlugin(ClipboardPlugin.class);
|
||||
PluginFactory.registerPlugin(BatteryPlugin.class);
|
||||
PluginFactory.registerPlugin(SftpPlugin.class);
|
||||
PluginFactory.registerPlugin(NotificationsPlugin.class);
|
||||
PluginFactory.registerPlugin(MousePadPlugin.class);
|
||||
PluginFactory.registerPlugin(SharePlugin.class);
|
||||
}
|
||||
|
||||
public static PluginInfo getPluginInfo(Context context, String pluginName) {
|
||||
@@ -76,7 +87,8 @@ public class PluginFactory {
|
||||
try {
|
||||
Plugin p = ((Plugin)availablePlugins.get(pluginName).newInstance());
|
||||
p.setContext(context, null);
|
||||
info = new PluginInfo(pluginName, p.getDisplayName(), p.getDescription(), p.getIcon(), p.isEnabledByDefault());
|
||||
info = new PluginInfo(pluginName, p.getDisplayName(), p.getDescription(), p.getIcon(),
|
||||
p.isEnabledByDefault(), p.hasSettings());
|
||||
availablePluginsInfo.put(pluginName, info); //Cache it
|
||||
return info;
|
||||
} catch(Exception e) {
|
||||
@@ -109,10 +121,10 @@ public class PluginFactory {
|
||||
|
||||
}
|
||||
|
||||
public static void registerPlugin(Class pluginClass) {
|
||||
public static void registerPlugin(Class<? extends Plugin> pluginClass) {
|
||||
try {
|
||||
//I hate this but I need to create an instance because abstract static functions can't be declared
|
||||
String pluginName = ((Plugin)pluginClass.newInstance()).getPluginName();
|
||||
String pluginName = (pluginClass.newInstance()).getPluginName();
|
||||
availablePlugins.put(pluginName, pluginClass);
|
||||
} catch(Exception e) {
|
||||
Log.e("PluginFactory","addPlugin exception");
|
||||
|
@@ -0,0 +1,210 @@
|
||||
package org.kde.kdeconnect.Plugins.SftpPlugin;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
|
||||
import org.apache.http.conn.util.InetAddressUtils;
|
||||
import org.apache.sshd.SshServer;
|
||||
import org.apache.sshd.common.NamedFactory;
|
||||
import org.apache.sshd.common.Session;
|
||||
import org.apache.sshd.server.Command;
|
||||
import org.apache.sshd.server.FileSystemFactory;
|
||||
import org.apache.sshd.server.FileSystemView;
|
||||
import org.apache.sshd.server.PasswordAuthenticator;
|
||||
import org.apache.sshd.server.PublickeyAuthenticator;
|
||||
import org.apache.sshd.server.SshFile;
|
||||
import org.apache.sshd.server.command.ScpCommandFactory;
|
||||
import org.apache.sshd.server.filesystem.NativeFileSystemView;
|
||||
import org.apache.sshd.server.filesystem.NativeSshFile;
|
||||
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 java.io.File;
|
||||
import java.net.InetAddress;
|
||||
import java.net.NetworkInterface;
|
||||
import java.net.SocketException;
|
||||
import java.security.PublicKey;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Enumeration;
|
||||
import java.util.List;
|
||||
|
||||
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;}
|
||||
|
||||
@Override
|
||||
public boolean authenticate(String user, String password, ServerSession session) {
|
||||
return user.equals(this.user) && password.equals(this.password);
|
||||
}
|
||||
|
||||
private String user;
|
||||
private String password;
|
||||
}
|
||||
|
||||
class SimplePublicKeyAuthenticator implements PublickeyAuthenticator {
|
||||
|
||||
private List<PublicKey> keys = new ArrayList<PublicKey>();
|
||||
|
||||
public void addKey(PublicKey key) {
|
||||
keys.add(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean authenticate(String user, PublicKey key, ServerSession session) {
|
||||
for (PublicKey k : keys) {
|
||||
if (key.equals(k)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class SimpleSftpServer {
|
||||
private static final int STARTPORT = 1739;
|
||||
private static final int ENDPORT = 1764;
|
||||
|
||||
private static final String USER = "kdeconnect";
|
||||
|
||||
public static int port = -1;
|
||||
private static boolean started = false;
|
||||
|
||||
public final SimplePasswordAuthenticator passwordAuth = new SimplePasswordAuthenticator();
|
||||
public final SimplePublicKeyAuthenticator keyAuth = new SimplePublicKeyAuthenticator();
|
||||
private final SshServer sshd = SshServer.setUpDefaultServer();
|
||||
|
||||
|
||||
public void init(Context ctx, Device device) {
|
||||
passwordAuth.setUser(USER);
|
||||
keyAuth.addKey(device.publicKey);
|
||||
sshd.setKeyPairProvider(new SimpleGeneratorHostKeyProvider(ctx.getFilesDir() + "/sftpd.ser"));
|
||||
|
||||
//sshd.setFileSystemFactory(new NativeFileSystemFactory());
|
||||
sshd.setFileSystemFactory(new SecureFileSystemFactory());
|
||||
//sshd.setShellFactory(new ProcessShellFactory(new String[] { "/bin/sh", "-i", "-l" }));
|
||||
sshd.setCommandFactory(new ScpCommandFactory());
|
||||
sshd.setSubsystemFactories(Arrays.<NamedFactory<Command>>asList(new SftpSubsystem.Factory()));
|
||||
|
||||
sshd.setPasswordAuthenticator(passwordAuth);
|
||||
sshd.setPublickeyAuthenticator(keyAuth);
|
||||
}
|
||||
|
||||
public boolean start() {
|
||||
if (!started) {
|
||||
String password = Long.toHexString(Double.doubleToLongBits(Math.random()));
|
||||
passwordAuth.setPassword(password);
|
||||
|
||||
port = STARTPORT;
|
||||
while(!started) {
|
||||
try {
|
||||
sshd.setPort(port);
|
||||
sshd.start();
|
||||
started = true;
|
||||
} catch(Exception e) {
|
||||
port++;
|
||||
if (port >= ENDPORT) {
|
||||
port = -1;
|
||||
Log.e("SftpServer", "No more ports available");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
try {
|
||||
started = false;
|
||||
sshd.stop();
|
||||
} catch (InterruptedException e) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public String getLocalIpAddress() {
|
||||
String ip6 = null;
|
||||
try {
|
||||
for (Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces(); en.hasMoreElements();) {
|
||||
NetworkInterface intf = en.nextElement();
|
||||
for (Enumeration<InetAddress> enumIpAddr = intf.getInetAddresses(); enumIpAddr.hasMoreElements();) {
|
||||
InetAddress inetAddress = enumIpAddr.nextElement();
|
||||
if (!inetAddress.isLoopbackAddress()) {
|
||||
String address = inetAddress.getHostAddress();
|
||||
if (InetAddressUtils.isIPv4Address(address)) { //Prefer IPv4 over IPv6, because sshfs doesn't seem to like IPv6
|
||||
return address;
|
||||
} else {
|
||||
ip6 = address;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (SocketException ex) {
|
||||
}
|
||||
return ip6;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class SecureFileSystemFactory implements FileSystemFactory {
|
||||
|
||||
public SecureFileSystemFactory() {}
|
||||
|
||||
@Override
|
||||
public FileSystemView createFileSystemView(final Session username) {
|
||||
final String base = "/";
|
||||
return new SecureFileSystemView(base, username.getUsername());
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
private boolean caseInsensitive = false;
|
||||
//
|
||||
public SecureFileSystemView(final String rootDir, final String userName) {
|
||||
super(userName);
|
||||
this.rootDir = NativeSshFile.normalizeSeparateChar(rootDir);
|
||||
this.userName = userName;
|
||||
}
|
||||
//
|
||||
@Override
|
||||
public SshFile getFile(final String file) {
|
||||
return getFile(currDir, file);
|
||||
}
|
||||
|
||||
@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
|
||||
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(this, userFileName, fileObj, userName);
|
||||
}
|
||||
}
|
||||
|
||||
class SecureSshFile extends NativeSshFile {
|
||||
//
|
||||
public SecureSshFile(final SecureFileSystemView view, final String fileName, final File file, final String userName) {
|
||||
super(fileName, file, userName);
|
||||
}
|
||||
}
|
@@ -0,0 +1,128 @@
|
||||
package org.kde.kdeconnect.Plugins.SftpPlugin;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.content.Context;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Environment;
|
||||
import android.widget.Button;
|
||||
|
||||
import org.kde.kdeconnect.Helpers.StorageHelper;
|
||||
import org.kde.kdeconnect.NetworkPackage;
|
||||
import org.kde.kdeconnect.Plugins.Plugin;
|
||||
import org.kde.kdeconnect_tp.R;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class SftpPlugin extends Plugin {
|
||||
|
||||
private static final SimpleSftpServer server = new SimpleSftpServer();
|
||||
|
||||
@Override
|
||||
public String getPluginName() {return "plugin_sftp";}
|
||||
|
||||
@Override
|
||||
public String getDisplayName() {
|
||||
return context.getResources().getString(R.string.pref_plugin_sftp);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return context.getResources().getString(R.string.pref_plugin_sftp_desc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Drawable getIcon() {
|
||||
return context.getResources().getDrawable(R.drawable.icon);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasSettings() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabledByDefault() { return true; }
|
||||
|
||||
@Override
|
||||
public boolean onCreate() {
|
||||
server.init(context, device);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
server.stop();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPackageReceived(NetworkPackage np) {
|
||||
if (!np.getType().equals(NetworkPackage.PACKAGE_TYPE_SFTP)) return false;
|
||||
|
||||
if (np.getBoolean("startBrowsing")) {
|
||||
if (server.start()) {
|
||||
|
||||
NetworkPackage np2 = new NetworkPackage(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());
|
||||
|
||||
//Kept for compatibility, but new desktop clients will read "multiPaths" instead,
|
||||
// that supports devices with more than one external storage
|
||||
np2.set("path", Environment.getExternalStorageDirectory().getAbsolutePath());
|
||||
|
||||
List<StorageHelper.StorageInfo> storageList = StorageHelper.getStorageList();
|
||||
ArrayList<String> paths = new ArrayList<String>();
|
||||
ArrayList<String> pathNames = new ArrayList<String>();
|
||||
|
||||
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));
|
||||
}
|
||||
} else {
|
||||
res.append(context.getString(R.string.sftp_all_files));
|
||||
}
|
||||
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 cameraDir = Environment.getExternalStorageDirectory().getAbsolutePath() + "/DCIM/Camera";
|
||||
if (new File(cameraDir).exists()) {
|
||||
paths.add(cameraDir);
|
||||
pathNames.add(context.getString(R.string.sftp_camera));
|
||||
}
|
||||
|
||||
np2.set("multiPaths", paths);
|
||||
np2.set("pathNames", pathNames);
|
||||
|
||||
device.sendPackage(np2);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AlertDialog getErrorDialog(Activity deviceActivity) { return null; }
|
||||
|
||||
@Override
|
||||
public Button getInterfaceButton(Activity activity) { return null; }
|
||||
|
||||
}
|
@@ -0,0 +1,255 @@
|
||||
package org.kde.kdeconnect.Plugins.SharePlugin;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.ClipboardManager;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.net.Uri;
|
||||
import android.os.Environment;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.support.v4.app.NotificationCompat;
|
||||
import android.support.v4.app.TaskStackBuilder;
|
||||
import android.util.Log;
|
||||
import android.widget.Button;
|
||||
import android.widget.Toast;
|
||||
|
||||
import org.kde.kdeconnect.Helpers.FilesHelper;
|
||||
import org.kde.kdeconnect.NetworkPackage;
|
||||
import org.kde.kdeconnect.Plugins.Plugin;
|
||||
import org.kde.kdeconnect_tp.R;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
|
||||
public class SharePlugin extends Plugin {
|
||||
|
||||
@Override
|
||||
public String getPluginName() {
|
||||
return "plugin_share";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayName() {
|
||||
return context.getResources().getString(R.string.pref_plugin_sharereceiver);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return context.getResources().getString(R.string.pref_plugin_sharereceiver_desc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Drawable getIcon() {
|
||||
return context.getResources().getDrawable(R.drawable.icon);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasSettings() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabledByDefault() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreate() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPackageReceived(NetworkPackage np) {
|
||||
|
||||
if (!np.getType().equals(NetworkPackage.PACKAGE_TYPE_SHARE)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
if (np.hasPayload()) {
|
||||
|
||||
Log.e("SharePlugin", "hasPayload");
|
||||
|
||||
final InputStream input = np.getPayload();
|
||||
final int fileLength = np.getPayloadSize();
|
||||
final String filename = np.getString("filename", new Long(System.currentTimeMillis()).toString());
|
||||
|
||||
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();
|
||||
|
||||
//Create directories if needed
|
||||
new File(destinationDir).mkdirs();
|
||||
|
||||
//Append filename to the destination path
|
||||
final File destinationFullPath = new File(destinationDir, filename);
|
||||
|
||||
Log.e("SharePlugin", "destinationFullPath:" + destinationFullPath);
|
||||
|
||||
final int notificationId = (int)System.currentTimeMillis();
|
||||
Resources res = context.getResources();
|
||||
Notification noti = new NotificationCompat.Builder(context)
|
||||
.setContentTitle(res.getString(R.string.incoming_file_title, device.getName()))
|
||||
.setContentText(res.getString(R.string.incoming_file_text, filename))
|
||||
.setTicker(res.getString(R.string.incoming_file_title, device.getName()))
|
||||
.setSmallIcon(android.R.drawable.ic_dialog_alert)
|
||||
.setAutoCancel(true)
|
||||
.build();
|
||||
|
||||
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
notificationManager.notify(notificationId, noti);
|
||||
|
||||
new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
OutputStream output = new FileOutputStream(destinationFullPath.getPath());
|
||||
|
||||
byte data[] = new byte[1024];
|
||||
long total = 0;
|
||||
int count;
|
||||
while ((count = input.read(data)) >= 0) {
|
||||
total += count;
|
||||
output.write(data, 0, count);
|
||||
if (fileLength > 0) {
|
||||
if (total >= fileLength) break;
|
||||
float progress = (total * 100 / fileLength);
|
||||
}
|
||||
//else Log.e("SharePlugin", "Infinite loop? :D");
|
||||
}
|
||||
|
||||
output.flush();
|
||||
output.close();
|
||||
input.close();
|
||||
|
||||
Log.e("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);
|
||||
|
||||
//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();
|
||||
|
||||
NotificationCompat.Builder builder = new NotificationCompat.Builder(context)
|
||||
.setContentTitle(res.getString(R.string.received_file_title, device.getName()))
|
||||
.setContentText(res.getString(R.string.received_file_text, filename))
|
||||
.setContentIntent(resultPendingIntent)
|
||||
.setTicker(res.getString(R.string.received_file_title, device.getName()))
|
||||
.setSmallIcon(android.R.drawable.ic_dialog_alert)
|
||||
.setAutoCancel(true);
|
||||
|
||||
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
if (prefs.getBoolean("share_notification_preference", true)) {
|
||||
builder.setDefaults(Notification.DEFAULT_ALL);
|
||||
}
|
||||
|
||||
Notification noti = builder.build();
|
||||
|
||||
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
notificationManager.notify(notificationId, noti);
|
||||
|
||||
} catch (Exception e) {
|
||||
Log.e("SharePlugin", "Receiver thread exception");
|
||||
e.printStackTrace();
|
||||
|
||||
}
|
||||
}
|
||||
}).start();
|
||||
|
||||
} else if (np.has("text")) {
|
||||
Log.e("SharePlugin", "hasText");
|
||||
|
||||
String text = np.getString("text");
|
||||
if(android.os.Build.VERSION.SDK_INT >= 11) {
|
||||
ClipboardManager cm = (ClipboardManager)context.getSystemService(Context.CLIPBOARD_SERVICE);
|
||||
cm.setText(text);
|
||||
} else {
|
||||
android.text.ClipboardManager clipboard = (android.text.ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
|
||||
clipboard.setText(text);
|
||||
}
|
||||
Toast.makeText(context, R.string.shareplugin_text_saved, Toast.LENGTH_LONG).show();
|
||||
} else if (np.has("url")) {
|
||||
|
||||
String url = np.getString("url");
|
||||
|
||||
Log.e("SharePlugin", "hasUrl: "+url);
|
||||
|
||||
Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
|
||||
browserIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
|
||||
//Do not launch it directly, show a notification instead
|
||||
//context.startActivity(browserIntent);
|
||||
|
||||
Resources res = context.getResources();
|
||||
TaskStackBuilder stackBuilder = TaskStackBuilder.create(context);
|
||||
stackBuilder.addNextIntent(browserIntent);
|
||||
PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(
|
||||
0,
|
||||
PendingIntent.FLAG_UPDATE_CURRENT
|
||||
);
|
||||
|
||||
Notification noti = new NotificationCompat.Builder(context)
|
||||
.setContentTitle(res.getString(R.string.received_url_title, device.getName()))
|
||||
.setContentText(res.getString(R.string.received_url_text, url))
|
||||
.setContentIntent(resultPendingIntent)
|
||||
.setTicker(res.getString(R.string.received_url_title, device.getName()))
|
||||
.setSmallIcon(android.R.drawable.ic_dialog_alert)
|
||||
.setAutoCancel(true)
|
||||
.setDefaults(Notification.DEFAULT_ALL)
|
||||
.build();
|
||||
|
||||
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
notificationManager.notify((int)System.currentTimeMillis(), noti);
|
||||
|
||||
} else {
|
||||
Log.e("SharePlugin", "Error: Nothing attached!");
|
||||
}
|
||||
|
||||
|
||||
} catch(Exception e) {
|
||||
Log.e("SharePlugin","Exception");
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AlertDialog getErrorDialog(Activity deviceActivity) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Button getInterfaceButton(Activity activity) { return null; }
|
||||
|
||||
}
|
@@ -10,7 +10,6 @@ import android.graphics.drawable.Drawable;
|
||||
import android.os.Bundle;
|
||||
import android.telephony.SmsMessage;
|
||||
import android.telephony.TelephonyManager;
|
||||
import android.util.Log;
|
||||
import android.widget.Button;
|
||||
|
||||
import org.kde.kdeconnect.Helpers.ContactsHelper;
|
||||
@@ -20,10 +19,6 @@ import org.kde.kdeconnect_tp.R;
|
||||
|
||||
public class TelephonyPlugin extends Plugin {
|
||||
|
||||
/*static {
|
||||
PluginFactory.registerPlugin(TelephonyPlugin.class);
|
||||
}*/
|
||||
|
||||
@Override
|
||||
public String getPluginName() {
|
||||
return "plugin_telephony";
|
||||
@@ -49,7 +44,12 @@ public class TelephonyPlugin extends Plugin {
|
||||
return true;
|
||||
}
|
||||
|
||||
private BroadcastReceiver receiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public boolean hasSettings() {
|
||||
return false;
|
||||
}
|
||||
|
||||
private final BroadcastReceiver receiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
|
||||
@@ -183,7 +183,7 @@ public class TelephonyPlugin extends Plugin {
|
||||
}
|
||||
|
||||
@Override
|
||||
public AlertDialog getErrorDialog(Context baseContext) {
|
||||
public AlertDialog getErrorDialog(Activity deviceActivity) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@@ -1,5 +1,6 @@
|
||||
package org.kde.kdeconnect.UserInterface;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.support.v7.app.ActionBar;
|
||||
@@ -8,8 +9,6 @@ import android.util.Log;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.Button;
|
||||
import android.widget.ListView;
|
||||
import android.widget.TextView;
|
||||
@@ -18,20 +17,27 @@ import org.kde.kdeconnect.BackgroundService;
|
||||
import org.kde.kdeconnect.Device;
|
||||
import org.kde.kdeconnect.Plugins.Plugin;
|
||||
import org.kde.kdeconnect.UserInterface.List.ButtonItem;
|
||||
import org.kde.kdeconnect.UserInterface.List.CustomItem;
|
||||
import org.kde.kdeconnect.UserInterface.List.ListAdapter;
|
||||
import org.kde.kdeconnect.UserInterface.List.SectionItem;
|
||||
import org.kde.kdeconnect.UserInterface.List.SmallEntryItem;
|
||||
import org.kde.kdeconnect.UserInterface.List.TextItem;
|
||||
import org.kde.kdeconnect_tp.R;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.ConcurrentModificationException;
|
||||
|
||||
public class DeviceActivity extends ActionBarActivity {
|
||||
|
||||
static private String deviceId; //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;
|
||||
|
||||
private Device.PluginsChangedListener pluginsChangedListener = new Device.PluginsChangedListener() {
|
||||
public static final int RESULT_NEEDS_RELOAD = Activity.RESULT_FIRST_USER;
|
||||
|
||||
TextView errorHeader;
|
||||
|
||||
private final Device.PluginsChangedListener pluginsChangedListener = new Device.PluginsChangedListener() {
|
||||
@Override
|
||||
public void onPluginsChanged(final Device device) {
|
||||
|
||||
@@ -39,42 +45,63 @@ public class DeviceActivity extends ActionBarActivity {
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
//Errors list
|
||||
final HashMap<String, Plugin> failedPlugins = device.getFailedPlugins();
|
||||
final String[] ids = failedPlugins.keySet().toArray(new String[failedPlugins.size()]);
|
||||
String[] names = new String[failedPlugins.size()];
|
||||
for(int i = 0; i < ids.length; i++) {
|
||||
Plugin p = failedPlugins.get(ids[i]);
|
||||
names[i] = p.getDisplayName();
|
||||
}
|
||||
ListView errorList = (ListView)findViewById(R.id.errors_list);
|
||||
if (!failedPlugins.isEmpty() && errorList.getHeaderViewsCount() == 0) {
|
||||
TextView header = new TextView(DeviceActivity.this);
|
||||
header.setPadding(0,24,0,0);
|
||||
header.setText(getResources().getString(R.string.plugins_failed_to_load));
|
||||
errorList.addHeaderView(header);
|
||||
}
|
||||
errorList.setAdapter(new ArrayAdapter<String>(DeviceActivity.this, android.R.layout.simple_list_item_1, names));
|
||||
errorList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {
|
||||
Plugin p = failedPlugins.get(ids[position - 1]); //Header is position 0, so we have to subtract one
|
||||
p.getErrorDialog(DeviceActivity.this).show();
|
||||
}
|
||||
});
|
||||
try {
|
||||
ArrayList<ListAdapter.Item> items = new ArrayList<ListAdapter.Item>();
|
||||
|
||||
//Buttons list
|
||||
ArrayList<ListAdapter.Item> items = new ArrayList<ListAdapter.Item>();
|
||||
final Collection<Plugin> plugins = device.getLoadedPlugins().values();
|
||||
for (Plugin p : plugins) {
|
||||
Button b = p.getInterfaceButton(DeviceActivity.this);
|
||||
if (b != null) {
|
||||
items.add(new SectionItem(p.getDisplayName()));
|
||||
if (!device.isReachable()) {
|
||||
//Not reachable, show unpair button
|
||||
Button b = new Button(DeviceActivity.this);
|
||||
b.setText(R.string.device_menu_unpair);
|
||||
b.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
device.unpair();
|
||||
finish();
|
||||
}
|
||||
});
|
||||
items.add(new TextItem(getString(R.string.device_not_reachable)));
|
||||
items.add(new ButtonItem(b));
|
||||
} else {
|
||||
//Plugins button list
|
||||
final Collection<Plugin> plugins = device.getLoadedPlugins().values();
|
||||
for (Plugin p : plugins) {
|
||||
Button b = p.getInterfaceButton(DeviceActivity.this);
|
||||
if (b != null) {
|
||||
items.add(new SectionItem(p.getDisplayName()));
|
||||
items.add(new ButtonItem(b));
|
||||
}
|
||||
}
|
||||
|
||||
//Failed plugins List
|
||||
final Collection<Plugin> failed = device.getFailedPlugins().values();
|
||||
if (!failed.isEmpty()) {
|
||||
if (errorHeader == null) {
|
||||
errorHeader = new TextView(DeviceActivity.this);
|
||||
errorHeader.setPadding(0, 48, 0, 0);
|
||||
errorHeader.setOnClickListener(null);
|
||||
errorHeader.setOnLongClickListener(null);
|
||||
errorHeader.setText(getResources().getString(R.string.plugins_failed_to_load));
|
||||
}
|
||||
items.add(new CustomItem(errorHeader));
|
||||
for (final Plugin p : failed) {
|
||||
items.add(new SmallEntryItem(p.getDisplayName(), new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
p.getErrorDialog(DeviceActivity.this).show();
|
||||
}
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ListView buttonsList = (ListView)findViewById(R.id.buttons_list);
|
||||
ListAdapter adapter = new ListAdapter(DeviceActivity.this, items);
|
||||
buttonsList.setAdapter(adapter);
|
||||
|
||||
} catch(ConcurrentModificationException e) {
|
||||
Log.e("DeviceActivity", "ConcurrentModificationException");
|
||||
this.run(); //Try again
|
||||
}
|
||||
ListView buttonsList = (ListView)findViewById(R.id.buttons_list);
|
||||
buttonsList.setAdapter(new ListAdapter(DeviceActivity.this, items));
|
||||
|
||||
}
|
||||
});
|
||||
@@ -103,6 +130,9 @@ public class DeviceActivity extends ActionBarActivity {
|
||||
setTitle(device.getName());
|
||||
device.addPluginsChangedListener(pluginsChangedListener);
|
||||
pluginsChangedListener.onPluginsChanged(device);
|
||||
if (!device.hasPluginsLoaded()) {
|
||||
device.reloadPluginsFromSettings();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -114,6 +144,7 @@ public class DeviceActivity extends ActionBarActivity {
|
||||
@Override
|
||||
public void onServiceStart(BackgroundService service) {
|
||||
Device device = service.getDevice(deviceId);
|
||||
if (device == null) return;
|
||||
device.removePluginsChangedListener(pluginsChangedListener);
|
||||
}
|
||||
});
|
||||
@@ -124,7 +155,7 @@ public class DeviceActivity extends ActionBarActivity {
|
||||
public boolean onPrepareOptionsMenu(Menu menu) {
|
||||
super.onPrepareOptionsMenu(menu);
|
||||
menu.clear();
|
||||
if (device.isPaired()) {
|
||||
if (device != null && device.isPaired()) {
|
||||
menu.add(R.string.device_menu_plugins).setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
|
||||
@Override
|
||||
public boolean onMenuItemClick(MenuItem menuItem) {
|
||||
@@ -146,6 +177,25 @@ public class DeviceActivity extends ActionBarActivity {
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
switch (requestCode)
|
||||
{
|
||||
case RESULT_NEEDS_RELOAD:
|
||||
BackgroundService.RunCommand(DeviceActivity.this, new BackgroundService.InstanceCallback() {
|
||||
@Override
|
||||
public void onServiceStart(BackgroundService service) {
|
||||
Device device = service.getDevice(deviceId);
|
||||
device.reloadPluginsFromSettings();
|
||||
}
|
||||
});
|
||||
break;
|
||||
default:
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@@ -0,0 +1,20 @@
|
||||
package org.kde.kdeconnect.UserInterface.List;
|
||||
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.Button;
|
||||
|
||||
public class CustomItem implements ListAdapter.Item {
|
||||
|
||||
private final View view;
|
||||
|
||||
public CustomItem(View v) {
|
||||
this.view = v;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View inflateView(LayoutInflater layoutInflater) {
|
||||
return view;
|
||||
}
|
||||
|
||||
}
|
@@ -4,6 +4,7 @@ package org.kde.kdeconnect.UserInterface.List;
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.widget.TextView;
|
||||
|
||||
@@ -24,7 +25,10 @@ public class DeviceItem implements ListAdapter.Item {
|
||||
|
||||
@Override
|
||||
public View inflateView(LayoutInflater layoutInflater) {
|
||||
View v = layoutInflater.inflate(R.layout.list_item_entry, null);
|
||||
final View v = layoutInflater.inflate(R.layout.list_item_entry, null);
|
||||
|
||||
//Highlight when selected effect
|
||||
v.setBackgroundDrawable(layoutInflater.getContext().getResources().getDrawable(R.drawable.kitkatcompatselector_list_selector_holo_dark));
|
||||
|
||||
TextView titleView = (TextView)v.findViewById(R.id.list_item_entry_title);
|
||||
if (titleView != null) titleView.setText(device.getName());
|
||||
|
@@ -1,15 +1,9 @@
|
||||
package org.kde.kdeconnect.UserInterface.List;
|
||||
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.kde.kdeconnect.Device;
|
||||
import org.kde.kdeconnect.UserInterface.DeviceActivity;
|
||||
import org.kde.kdeconnect.UserInterface.PairActivity;
|
||||
import org.kde.kdeconnect_tp.R;
|
||||
|
||||
public class EntryItem implements ListAdapter.Item {
|
||||
|
@@ -14,8 +14,8 @@ public class ListAdapter extends ArrayAdapter<ListAdapter.Item> {
|
||||
public View inflateView(LayoutInflater layoutInflater);
|
||||
}
|
||||
|
||||
private ArrayList<Item> items;
|
||||
private LayoutInflater layoutInflater;
|
||||
private final ArrayList<Item> items;
|
||||
private final LayoutInflater layoutInflater;
|
||||
|
||||
public ListAdapter(Context context, ArrayList<Item> items) {
|
||||
super(context, 0, items);
|
||||
|
@@ -9,11 +9,11 @@ import org.kde.kdeconnect_tp.R;
|
||||
public class SectionItem implements ListAdapter.Item {
|
||||
|
||||
private final String title;
|
||||
public boolean isEmpty;
|
||||
public boolean isSectionEmpty;
|
||||
|
||||
public SectionItem(String title) {
|
||||
this.title = title;
|
||||
this.isEmpty = false;
|
||||
this.isSectionEmpty = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -21,14 +21,14 @@ public class SectionItem implements ListAdapter.Item {
|
||||
|
||||
View v = layoutInflater.inflate(R.layout.list_item_category, null);
|
||||
|
||||
//Make it not selectable
|
||||
v.setOnClickListener(null);
|
||||
v.setOnLongClickListener(null);
|
||||
v.setLongClickable(false);
|
||||
|
||||
TextView sectionView = (TextView) v.findViewById(R.id.list_item_category_text);
|
||||
sectionView.setText(title);
|
||||
|
||||
if (isEmpty) {
|
||||
if (isSectionEmpty) {
|
||||
v.findViewById(R.id.list_item_category_empty_placeholder).setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
|
@@ -0,0 +1,40 @@
|
||||
package org.kde.kdeconnect.UserInterface.List;
|
||||
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.kde.kdeconnect_tp.R;
|
||||
|
||||
public class SmallEntryItem implements ListAdapter.Item {
|
||||
|
||||
private final String title;
|
||||
private final View.OnClickListener clickListener;
|
||||
|
||||
public SmallEntryItem(String title) {
|
||||
this.title = title;
|
||||
this.clickListener = null;
|
||||
}
|
||||
|
||||
public SmallEntryItem(String title, View.OnClickListener clickListener) {
|
||||
this.title = title;
|
||||
this.clickListener = clickListener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View inflateView(LayoutInflater layoutInflater) {
|
||||
View v = layoutInflater.inflate(android.R.layout.simple_list_item_1, null);
|
||||
|
||||
TextView titleView = (TextView)v.findViewById(android.R.id.text1);
|
||||
if (titleView != null) titleView.setText(title);
|
||||
if (clickListener != null) {
|
||||
titleView.setOnClickListener(clickListener);
|
||||
v.setBackgroundDrawable(layoutInflater.getContext().getResources().getDrawable(R.drawable.kitkatcompatselector_list_selector_holo_dark));
|
||||
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,27 @@
|
||||
package org.kde.kdeconnect.UserInterface.List;
|
||||
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.TextView;
|
||||
|
||||
import android.R;
|
||||
|
||||
public class TextItem implements ListAdapter.Item {
|
||||
|
||||
private final String title;
|
||||
|
||||
public TextItem(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View inflateView(LayoutInflater layoutInflater) {
|
||||
|
||||
TextView v = new TextView(layoutInflater.getContext());
|
||||
v.setText(title);
|
||||
v.setTextAppearance(layoutInflater.getContext(), R.style.TextAppearance_DeviceDefault_Medium);
|
||||
return v;
|
||||
|
||||
}
|
||||
|
||||
}
|
@@ -6,7 +6,6 @@ import android.content.res.Resources;
|
||||
import android.os.Bundle;
|
||||
import android.support.v7.app.ActionBar;
|
||||
import android.support.v7.app.ActionBarActivity;
|
||||
import android.util.Log;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
@@ -105,36 +104,36 @@ public class MainActivity extends ActionBarActivity {
|
||||
Resources res = getResources();
|
||||
|
||||
section = new SectionItem(res.getString(R.string.category_connected_devices));
|
||||
section.isEmpty = true;
|
||||
section.isSectionEmpty = true;
|
||||
items.add(section);
|
||||
for(Device d : devices) {
|
||||
if (d.isReachable() && d.isPaired()) {
|
||||
items.add(new DeviceItem(MainActivity.this, d));
|
||||
section.isEmpty = false;
|
||||
section.isSectionEmpty = false;
|
||||
}
|
||||
}
|
||||
|
||||
section = new SectionItem(res.getString(R.string.category_not_paired_devices));
|
||||
section.isEmpty = true;
|
||||
section.isSectionEmpty = true;
|
||||
items.add(section);
|
||||
for(Device d : devices) {
|
||||
if (d.isReachable() && !d.isPaired()) {
|
||||
items.add(new DeviceItem(MainActivity.this, d));
|
||||
section.isEmpty = false;
|
||||
section.isSectionEmpty = false;
|
||||
}
|
||||
}
|
||||
|
||||
section = new SectionItem(res.getString(R.string.category_remembered_devices));
|
||||
section.isEmpty = true;
|
||||
section.isSectionEmpty = true;
|
||||
items.add(section);
|
||||
for(Device d : devices) {
|
||||
if (!d.isReachable() && d.isPaired()) {
|
||||
items.add(new DeviceItem(MainActivity.this, d));
|
||||
section.isEmpty = false;
|
||||
section.isSectionEmpty = false;
|
||||
}
|
||||
}
|
||||
if (section.isEmpty) {
|
||||
items.remove(items.size()-1); //Remove section
|
||||
if (section.isSectionEmpty) {
|
||||
items.remove(items.size()-1); //Remove remembered devices section if empty
|
||||
}
|
||||
|
||||
runOnUiThread(new Runnable() {
|
||||
@@ -145,12 +144,13 @@ public class MainActivity extends ActionBarActivity {
|
||||
list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
|
||||
view.callOnClick();
|
||||
view.performClick();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@@ -13,10 +13,11 @@ import android.preference.PreferenceManager;
|
||||
import android.util.Log;
|
||||
import android.widget.Toast;
|
||||
|
||||
import org.kde.kdeconnect.BackgroundService;
|
||||
import org.kde.kdeconnect.Helpers.DeviceHelper;
|
||||
import org.kde.kdeconnect_tp.R;
|
||||
|
||||
public class MainSettingsActivity extends PreferenceActivity{
|
||||
public class MainSettingsActivity extends PreferenceActivity {
|
||||
|
||||
public static final String KEY_DEVICE_NAME_PREFERENCE = "device_name_preference";
|
||||
|
||||
@@ -55,6 +56,14 @@ public class MainSettingsActivity extends PreferenceActivity{
|
||||
deviceNamePref.setSummary(getString(
|
||||
R.string.device_name_preference_summary,
|
||||
newDeviceName.toString()));
|
||||
|
||||
//Broadcast the device information again since it has changed
|
||||
BackgroundService.RunCommand(MainSettingsActivity.this, new BackgroundService.InstanceCallback() {
|
||||
@Override
|
||||
public void onServiceStart(BackgroundService service) {
|
||||
service.onNetworkChange();
|
||||
}
|
||||
});
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -67,7 +76,7 @@ public class MainSettingsActivity extends PreferenceActivity{
|
||||
/**
|
||||
* Until now it sets only the default deviceName (if not already set).
|
||||
* It's safe to call this multiple time because doesn't override any previous value.
|
||||
* @param context
|
||||
* @param context the application context
|
||||
*/
|
||||
public static void initializeDeviceName(Context context){
|
||||
// I could have used getDefaultSharedPreferences(context).contains but we need to check
|
||||
|
@@ -0,0 +1,35 @@
|
||||
package org.kde.kdeconnect.UserInterface;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.util.AttributeSet;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import org.kde.kdeconnect_tp.R;
|
||||
|
||||
public class MaxWidthImageButton extends ImageButton {
|
||||
|
||||
int mMaxWidth = Integer.MAX_VALUE;
|
||||
|
||||
public MaxWidthImageButton(Context context) {
|
||||
|
||||
super(context);
|
||||
}
|
||||
|
||||
public MaxWidthImageButton(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
|
||||
TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.MaxWidthImageButton);
|
||||
mMaxWidth = a.getDimensionPixelSize(R.styleable.MaxWidthImageButton_maxWidth, Integer.MAX_VALUE);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
||||
if(getMeasuredWidth() > mMaxWidth){
|
||||
setMeasuredDimension(mMaxWidth, getMeasuredHeight());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -18,7 +18,7 @@ public class PairActivity extends ActionBarActivity {
|
||||
private String deviceId;
|
||||
private Device device = null;
|
||||
|
||||
private Device.PairingCallback pairingCallback = new Device.PairingCallback() {
|
||||
private final Device.PairingCallback pairingCallback = new Device.PairingCallback() {
|
||||
|
||||
@Override
|
||||
public void incomingRequest() {
|
||||
@@ -76,6 +76,7 @@ public class PairActivity extends ActionBarActivity {
|
||||
@Override
|
||||
public void onServiceStart(BackgroundService service) {
|
||||
device = service.getDevice(deviceId);
|
||||
if (device == null) return;
|
||||
setTitle(device.getName());
|
||||
NotificationManager notificationManager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
notificationManager.cancel(device.getNotificationId());
|
||||
@@ -94,6 +95,7 @@ public class PairActivity extends ActionBarActivity {
|
||||
@Override
|
||||
public void onServiceStart(BackgroundService service) {
|
||||
device = service.getDevice(deviceId);
|
||||
if (device == null) return;
|
||||
device.requestPairing();
|
||||
}
|
||||
});
|
||||
@@ -134,6 +136,8 @@ public class PairActivity extends ActionBarActivity {
|
||||
BackgroundService.RunCommand(PairActivity.this, new BackgroundService.InstanceCallback() {
|
||||
@Override
|
||||
public void onServiceStart(BackgroundService service) {
|
||||
device = service.getDevice(deviceId);
|
||||
if (device == null) return;
|
||||
device.addPairingCallback(pairingCallback);
|
||||
}
|
||||
});
|
||||
|
@@ -0,0 +1,17 @@
|
||||
package org.kde.kdeconnect.UserInterface;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.preference.PreferenceActivity;
|
||||
|
||||
public class PluginSettingsActivity extends PreferenceActivity {
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
String resource_name = getIntent().getStringExtra(Intent.EXTRA_INTENT);
|
||||
int resource_file = getResources().getIdentifier(resource_name, "xml", getPackageName());
|
||||
addPreferencesFromResource(resource_file);
|
||||
}
|
||||
}
|
@@ -1,28 +0,0 @@
|
||||
package org.kde.kdeconnect.UserInterface;
|
||||
|
||||
import android.content.Context;
|
||||
import android.preference.Preference;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ArrayAdapter;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class PreferenceListAdapter extends ArrayAdapter<Preference> {
|
||||
|
||||
|
||||
private ArrayList<Preference> localList;
|
||||
|
||||
public PreferenceListAdapter(Context context, ArrayList<Preference> items) {
|
||||
super(context,0, items);
|
||||
localList = items;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
Preference preference = localList.get(position);
|
||||
return preference.getView(convertView, parent);
|
||||
}
|
||||
|
||||
}
|
@@ -1,27 +1,36 @@
|
||||
package org.kde.kdeconnect.UserInterface;
|
||||
|
||||
import android.app.ListActivity;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.preference.CheckBoxPreference;
|
||||
import android.preference.Preference;
|
||||
import android.util.Log;
|
||||
import android.preference.PreferenceActivity;
|
||||
import android.preference.PreferenceScreen;
|
||||
import android.view.View;
|
||||
import android.widget.AdapterView;
|
||||
|
||||
import org.kde.kdeconnect.BackgroundService;
|
||||
import org.kde.kdeconnect.Device;
|
||||
import org.kde.kdeconnect.Plugins.PluginFactory;
|
||||
import org.kde.kdeconnect_tp.R;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Set;
|
||||
|
||||
public class SettingsActivity extends ListActivity {
|
||||
public class SettingsActivity extends PreferenceActivity {
|
||||
|
||||
static private String deviceId; //Static because if we get here by using the back button in the action bar, the extra deviceId will not be set.
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
final PreferenceScreen preferenceScreen = getPreferenceManager().createPreferenceScreen(this);
|
||||
setPreferenceScreen(preferenceScreen);
|
||||
|
||||
if (getIntent().hasExtra("deviceId")) {
|
||||
deviceId = getIntent().getStringExtra("deviceId");
|
||||
}
|
||||
|
||||
final String deviceId = getIntent().getStringExtra("deviceId");
|
||||
BackgroundService.RunCommand(getApplicationContext(), new BackgroundService.InstanceCallback() {
|
||||
@Override
|
||||
public void onServiceStart(BackgroundService service) {
|
||||
@@ -31,40 +40,49 @@ public class SettingsActivity extends ListActivity {
|
||||
|
||||
final ArrayList<Preference> preferences = new ArrayList<Preference>();
|
||||
for (final String pluginName : plugins) {
|
||||
CheckBoxPreference pref = new CheckBoxPreference(getBaseContext());
|
||||
final CheckBoxPreference pref = new CheckBoxPreference(getBaseContext());
|
||||
|
||||
PluginFactory.PluginInfo info = PluginFactory.getPluginInfo(getBaseContext(), pluginName);
|
||||
pref.setKey(pluginName);
|
||||
pref.setTitle(info.getDisplayName());
|
||||
pref.setSummary(info.getDescription());
|
||||
pref.setChecked(device.isPluginEnabled(pluginName));
|
||||
preferences.add(pref);
|
||||
preferenceScreen.addPreference(pref);
|
||||
|
||||
if (info.hasSettings()) {
|
||||
final Preference pluginPreference = new Preference(getBaseContext());
|
||||
pluginPreference.setKey(pluginName + getString(R.string.plugin_settings_key));
|
||||
pluginPreference.setTitle(info.getDisplayName());
|
||||
pluginPreference.setSummary(R.string.plugin_settings);
|
||||
preferences.add(pluginPreference);
|
||||
preferenceScreen.addPreference(pluginPreference);
|
||||
pluginPreference.setDependency(pref.getKey());
|
||||
}
|
||||
}
|
||||
|
||||
setListAdapter(new PreferenceListAdapter(SettingsActivity.this, preferences));
|
||||
getListView().setOnItemClickListener(new AdapterView.OnItemClickListener() {
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
|
||||
|
||||
CheckBoxPreference pref = (CheckBoxPreference)preferences.get(i);
|
||||
|
||||
boolean enabled = device.isPluginEnabled(pref.getKey());
|
||||
device.setPluginEnabled(pref.getKey(), !enabled);
|
||||
|
||||
pref.setChecked(!enabled);
|
||||
|
||||
getListAdapter().getView(i, view, null); //This will refresh the view (yes, this is the way to do it)
|
||||
|
||||
Preference pref = preferences.get(i);
|
||||
if (pref.getDependency() == null) { //Is a plugin check
|
||||
CheckBoxPreference check = (CheckBoxPreference)pref;
|
||||
boolean enabled = device.isPluginEnabled(pref.getKey());
|
||||
device.setPluginEnabled(pref.getKey(), !enabled);
|
||||
check.setChecked(!enabled);
|
||||
} else { //Is a plugin suboption
|
||||
if (pref.isEnabled()) {
|
||||
Intent intent = new Intent(SettingsActivity.this, PluginSettingsActivity.class);
|
||||
intent.putExtra(Intent.EXTRA_INTENT, pref.getKey());
|
||||
startActivity(intent);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
getListView().setPadding(16,16,16,16);
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
@@ -136,7 +136,8 @@ public class ShareToReceiver extends ActionBarActivity {
|
||||
queuedSendUriList(device, uriList);
|
||||
|
||||
} catch (Exception e) {
|
||||
Log.e(this.getClass().getName(), e.toString());
|
||||
e.printStackTrace();
|
||||
Log.e("ShareToReceiver", "Exception");
|
||||
}
|
||||
|
||||
} else if (extras.containsKey(Intent.EXTRA_TEXT)) {
|
||||
@@ -180,6 +181,9 @@ public class ShareToReceiver extends ActionBarActivity {
|
||||
|
||||
if (uri.getScheme().equals("file")) {
|
||||
// file:// is a non media uri, so we cannot query the ContentProvider
|
||||
|
||||
np.set("filename", uri.getLastPathSegment());
|
||||
|
||||
try {
|
||||
size = (int)new File(uri.getPath()).length();
|
||||
np.setPayload(inputStream, size);
|
||||
@@ -187,35 +191,23 @@ public class ShareToReceiver extends ActionBarActivity {
|
||||
e.printStackTrace();
|
||||
Log.e("ShareToReceiver", "Could not obtain file size");
|
||||
}
|
||||
try{
|
||||
np.set("filename", uri.getLastPathSegment());
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
Log.e("ShareToReceiver", "Could not obtain file name");
|
||||
}
|
||||
|
||||
}else{
|
||||
// Probably a content:// uri, so we query the Media content provider
|
||||
String[] proj = { MediaStore.MediaColumns.DATA, MediaStore.MediaColumns.SIZE, MediaStore.MediaColumns.DISPLAY_NAME };
|
||||
Cursor cursor = managedQuery(uri, proj, null, null, null);
|
||||
try {
|
||||
int column_index = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.SIZE);
|
||||
cursor.moveToFirst();
|
||||
size = cursor.getInt(column_index);
|
||||
} catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
Log.e("ShareToReceiver", "Could not obtain file size");
|
||||
}
|
||||
|
||||
//Log.e("ShareToReceiver", "Size "+size);
|
||||
np.setPayload(inputStream, size);
|
||||
|
||||
Cursor cursor = null;
|
||||
try {
|
||||
String[] proj = { MediaStore.MediaColumns.DATA, MediaStore.MediaColumns.SIZE, MediaStore.MediaColumns.DISPLAY_NAME };
|
||||
cursor = getContentResolver().query(uri, proj, null, null, null);
|
||||
int column_index = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DATA);
|
||||
cursor.moveToFirst();
|
||||
String path = cursor.getString(column_index);
|
||||
np.set("filename", Uri.parse(path).getLastPathSegment());
|
||||
} catch(Exception _) {
|
||||
np.set("size", (int)new File(path).length());
|
||||
} catch(Exception unused) {
|
||||
|
||||
Log.e("ShareToReceiver", "Could not resolve media to a file, trying to get info as media");
|
||||
|
||||
try {
|
||||
int column_index = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DISPLAY_NAME);
|
||||
cursor.moveToFirst();
|
||||
@@ -225,9 +217,22 @@ public class ShareToReceiver extends ActionBarActivity {
|
||||
e.printStackTrace();
|
||||
Log.e("ShareToReceiver", "Could not obtain file name");
|
||||
}
|
||||
|
||||
try {
|
||||
int column_index = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.SIZE);
|
||||
cursor.moveToFirst();
|
||||
//For some reason this size can differ from the actual file size!
|
||||
size = cursor.getInt(column_index);
|
||||
} catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
Log.e("ShareToReceiver", "Could not obtain file size");
|
||||
}
|
||||
} finally {
|
||||
cursor.close();
|
||||
}
|
||||
|
||||
cursor.close();
|
||||
np.setPayload(inputStream, size);
|
||||
|
||||
}
|
||||
|
||||
device.sendPackage(np, new Device.SendPackageFinishedCallback() {
|
||||
|
BIN
src/main/res/drawable-hdpi/ic_action_keyboard.png
Normal file
After Width: | Height: | Size: 351 B |
BIN
src/main/res/drawable-hdpi/icon.png
Normal file
After Width: | Height: | Size: 5.0 KiB |
After Width: | Height: | Size: 115 B |
After Width: | Height: | Size: 139 B |
After Width: | Height: | Size: 115 B |
After Width: | Height: | Size: 115 B |
After Width: | Height: | Size: 189 B |
BIN
src/main/res/drawable-ldpi/icon.png
Normal file
After Width: | Height: | Size: 2.0 KiB |
BIN
src/main/res/drawable-mdpi/ic_action_keyboard.png
Normal file
After Width: | Height: | Size: 431 B |
After Width: | Height: | Size: 110 B |
After Width: | Height: | Size: 117 B |
After Width: | Height: | Size: 110 B |
After Width: | Height: | Size: 110 B |
After Width: | Height: | Size: 172 B |
BIN
src/main/res/drawable-xhdpi/ic_action_keyboard.png
Normal file
After Width: | Height: | Size: 451 B |
BIN
src/main/res/drawable-xhdpi/icon.png
Normal file
After Width: | Height: | Size: 7.0 KiB |
After Width: | Height: | Size: 121 B |
After Width: | Height: | Size: 154 B |
After Width: | Height: | Size: 121 B |
After Width: | Height: | Size: 121 B |
After Width: | Height: | Size: 190 B |
BIN
src/main/res/drawable-xxhdpi/ic_action_keyboard.png
Normal file
After Width: | Height: | Size: 468 B |
BIN
src/main/res/drawable-xxhdpi/icon.png
Normal file
After Width: | Height: | Size: 42 KiB |
After Width: | Height: | Size: 133 B |
After Width: | Height: | Size: 158 B |
After Width: | Height: | Size: 133 B |
After Width: | Height: | Size: 133 B |
After Width: | Height: | Size: 273 B |
Before Width: | Height: | Size: 750 B After Width: | Height: | Size: 750 B |
Before Width: | Height: | Size: 365 B After Width: | Height: | Size: 365 B |
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 1.0 KiB |
Before Width: | Height: | Size: 6.7 KiB After Width: | Height: | Size: 3.0 KiB |
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2008 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:state_activated="true" android:drawable="@drawable/kitkatcompatselector_list_activated_holo" />
|
||||
<item android:drawable="@android:color/transparent" />
|
||||
</selector>
|
@@ -0,0 +1,26 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2010 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<!-- Even though these two point to the same resource, have two states so the drawable will invalidate itself when coming out of pressed state. -->
|
||||
<item android:state_focused="true" android:state_enabled="false" android:state_pressed="true" android:drawable="@drawable/kitkatcompatselector_list_selector_disabled_holo_dark" />
|
||||
<item android:state_focused="true" android:state_enabled="false" android:drawable="@drawable/kitkatcompatselector_list_selector_disabled_holo_dark" />
|
||||
<item android:state_focused="true" android:state_pressed="true" android:drawable="@drawable/kitkatcompatselector_list_selector_background_transition_holo_dark" />
|
||||
<item android:state_focused="false" android:state_pressed="true" android:drawable="@drawable/kitkatcompatselector_list_selector_background_transition_holo_dark" />
|
||||
<item android:state_focused="true" android:drawable="@drawable/kitkatcompatselector_list_focused_holo" />
|
||||
<item android:drawable="@android:color/transparent" />
|
||||
</selector>
|
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2010 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<transition xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:drawable="@drawable/kitkatcompatselector_list_pressed_holo_dark" />
|
||||
<item android:drawable="@drawable/kitkatcompatselector_list_longpressed_holo" />
|
||||
</transition>
|
@@ -0,0 +1,27 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2010 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<item android:state_window_focused="false" android:drawable="@android:color/transparent" />
|
||||
|
||||
<!-- Even though these two point to the same resource, have two states so the drawable will invalidate itself when coming out of pressed state. -->
|
||||
<item android:state_focused="true" android:state_enabled="false" android:state_pressed="true" android:drawable="@drawable/kitkatcompatselector_list_selector_disabled_holo_dark" />
|
||||
<item android:state_focused="true" android:state_enabled="false" android:drawable="@drawable/kitkatcompatselector_list_selector_disabled_holo_dark" />
|
||||
<item android:state_focused="true" android:state_pressed="true" android:drawable="@drawable/kitkatcompatselector_list_selector_background_transition_holo_dark" />
|
||||
<item android:state_focused="false" android:state_pressed="true" android:drawable="@drawable/kitkatcompatselector_list_selector_background_transition_holo_dark" />
|
||||
<item android:state_focused="true" android:drawable="@drawable/kitkatcompatselector_list_focused_holo" />
|
||||
</selector>
|
@@ -1,26 +1,13 @@
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<ListView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/buttons_list"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:paddingLeft="@dimen/activity_horizontal_margin"
|
||||
android:paddingRight="@dimen/activity_horizontal_margin"
|
||||
android:paddingTop="@dimen/activity_vertical_margin"
|
||||
android:paddingBottom="@dimen/activity_vertical_margin"
|
||||
android:fillViewport="true"
|
||||
android:divider="@null"
|
||||
tools:context=".MainActivity"
|
||||
android:orientation="vertical">
|
||||
|
||||
<ListView
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:id="@+id/buttons_list"
|
||||
android:layout_weight="1"
|
||||
/>
|
||||
|
||||
<ListView
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:id="@+id/errors_list"
|
||||
android:layout_weight="1"
|
||||
/>
|
||||
|
||||
</LinearLayout>
|
||||
/>
|
27
src/main/res/layout/activity_mousepad.xml
Normal file
@@ -0,0 +1,27 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:id="@+id/mousepad_view">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/mousepad_info"
|
||||
android:gravity="center"
|
||||
style="@android:style/TextAppearance.Medium"
|
||||
android:layout_centerInParent="true"
|
||||
android:padding="12dip" />
|
||||
|
||||
<view
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
class="org.kde.kdeconnect.Plugins.MousePadPlugin.KeyListenerView"
|
||||
android:id="@+id/keyListener"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:layout_marginTop="58dp" />
|
||||
|
||||
</RelativeLayout>
|
@@ -1,43 +1,52 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:id="@+id/mpris_control_view"
|
||||
android:gravity="center">
|
||||
android:gravity="center"
|
||||
android:paddingLeft="60dip"
|
||||
android:paddingTop="5dip"
|
||||
android:paddingRight="60dip"
|
||||
android:paddingBottom="5dip">
|
||||
|
||||
<Spinner
|
||||
android:layout_width="200dip"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/player_spinner"
|
||||
android:layout_gravity="center"
|
||||
/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
android:id="@+id/now_playing_textview"
|
||||
android:singleLine="true"
|
||||
android:gravity="center"
|
||||
android:padding="5dip"
|
||||
android:padding="8dip"
|
||||
android:layout_gravity="center"
|
||||
/>
|
||||
|
||||
<ImageButton
|
||||
android:layout_width="200dip"
|
||||
<org.kde.kdeconnect.UserInterface.MaxWidthImageButton
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="75dip"
|
||||
app:maxWidth="300dip"
|
||||
android:id="@+id/play_button"
|
||||
android:src="@android:drawable/ic_media_play"
|
||||
android:contentDescription="@string/mpris_play"
|
||||
android:layout_gravity="center"
|
||||
/>
|
||||
android:layout_weight="0"
|
||||
android:clickable="false"
|
||||
android:adjustViewBounds="false"
|
||||
android:baselineAlignBottom="true" />
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="200dip"
|
||||
android:layout_height="50dip"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="60dip"
|
||||
android:layout_gravity="center"
|
||||
>
|
||||
|
||||
@@ -81,17 +90,18 @@
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="200dip"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="70dip"
|
||||
android:id="@+id/volume_layout"
|
||||
android:layout_gravity="center">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="50dip"
|
||||
android:layout_height="50dip"
|
||||
android:layout_width="30dip"
|
||||
android:layout_height="30dip"
|
||||
android:maxWidth="30dip"
|
||||
android:layout_marginRight="10dip"
|
||||
android:id="@+id/imageView"
|
||||
android:layout_weight="1"
|
||||
android:layout_weight="0"
|
||||
android:layout_gravity="left|center_vertical"
|
||||
android:contentDescription="@string/mpris_volume"
|
||||
android:src="@drawable/ic_volume"
|
||||
@@ -99,7 +109,7 @@
|
||||
|
||||
|
||||
<SeekBar
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/volume_seek"
|
||||
android:layout_weight="1"
|
||||
|
@@ -5,7 +5,7 @@
|
||||
android:id="@+id/menu_refresh"
|
||||
android:icon="@drawable/ic_action_refresh"
|
||||
android:orderInCategory="200"
|
||||
kdeconnect:showAsAction="always"
|
||||
kdeconnect:showAsAction="ifRoom"
|
||||
android:title="@string/reconnect"
|
||||
/>
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
android:id="@+id/menu_progress"
|
||||
android:orderInCategory="200"
|
||||
android:visible="false"
|
||||
kdeconnect:showAsAction="always"
|
||||
kdeconnect:showAsAction="ifRoom"
|
||||
kdeconnect:actionViewClass="android.widget.ProgressBar"
|
||||
/>
|
||||
|
||||
|
18
src/main/res/menu/menu_mousepad.xml
Normal file
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:kdeconnect="http://schemas.android.com/apk/res-auto/android">
|
||||
|
||||
<item android:id="@+id/menu_show_keyboard"
|
||||
android:title="@string/show_keyboard"
|
||||
android:icon="@drawable/ic_action_keyboard"
|
||||
kdeconnect:showAsAction="ifRoom" />
|
||||
|
||||
<item android:id="@+id/menu_right_click"
|
||||
android:title="@string/right_click"
|
||||
kdeconnect:showAsAction="never" />
|
||||
|
||||
<item android:id="@+id/menu_middle_click"
|
||||
android:title="@string/middle_click"
|
||||
kdeconnect:showAsAction="never" />
|
||||
|
||||
</menu>
|
80
src/main/res/values-bg/strings.xml
Normal file
@@ -0,0 +1,80 @@
|
||||
<?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_mpris">Отдалечен мултимедиен контрол</string>
|
||||
<string name="pref_plugin_mpris_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="plugin_not_available">Тази функция не е налична във вашата версия на Андроид</string>
|
||||
<string name="device_list_empty">Няма устройства</string>
|
||||
<string name="ok">Добре</string>
|
||||
<string name="cancel">Отказ</string>
|
||||
<string name="open_settings">Отваряне на настройките</string>
|
||||
<string name="no_permissions">Трябва да осигурите права за достъп до уведомленията</string>
|
||||
<string name="send_ping">Изпращане на пинг</string>
|
||||
<string name="open_mpris_controls">Отваряне на отдалечен контрол</string>
|
||||
<string name="open_mousepad">Отваряне на отдалечен контрол</string>
|
||||
<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="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="pair_requested">Заявено е сдвояване</string>
|
||||
<string name="pairing_request_from">Заявено е сдвояване от %1s</string>
|
||||
<string name="incoming_file_title">Заявено е сдвояване от %1s</string>
|
||||
<string name="incoming_file_text">%s</string>
|
||||
<string name="tap_to_answer">Докоснете за да отговорите</string>
|
||||
<string name="reconnect">Ново свързване</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 Connect</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="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="device_name">Име на устройството</string>
|
||||
<string name="device_name_preference_summary">%s</string>
|
||||
<string name="invalid_device_name">Невалидно име на устройство</string>
|
||||
<string name="share_notification_preference">Синхронизиране на уведомленията</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>
|
||||
</string-array>
|
||||
</resources>
|
16
src/main/res/values-bs/strings.xml
Normal file
@@ -0,0 +1,16 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<resources>
|
||||
<string name="pref_plugin_battery">Baterijski izvještaj</string>
|
||||
<string name="pref_plugin_battery_desc">Periodično javi baterijski status</string>
|
||||
<string name="pref_plugin_ping">Ping</string>
|
||||
<string name="pref_plugin_ping_desc">Šalji i primaj ping-ove</string>
|
||||
<string name="pref_plugin_notifications">Sinhronizovano obavještenje</string>
|
||||
<string name="share_notification_preference">Sinhronizovano obavještenje</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>
|
||||
</string-array>
|
||||
</resources>
|
101
src/main/res/values-ca/strings.xml
Normal file
@@ -0,0 +1,101 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<resources>
|
||||
<string name="pref_plugin_telephony">Notificador de telefonia</string>
|
||||
<string name="pref_plugin_telephony_desc">Envia notificacions pels SMS i les trucades</string>
|
||||
<string name="pref_plugin_battery">Informe de la bateria</string>
|
||||
<string name="pref_plugin_battery_desc">Informa periòdicament sobre l\'estat de la bateria</string>
|
||||
<string name="pref_plugin_sftp">Exposa el sistema de fitxers</string>
|
||||
<string name="pref_plugin_sftp_desc">Permet navegar de forma remota pel sistema de fitxers del telèfon</string>
|
||||
<string name="pref_plugin_clipboard">Sincronitza el porta-retalls</string>
|
||||
<string name="pref_plugin_clipboard_desc">Comparteix el contingut del porta-retalls</string>
|
||||
<string name="pref_plugin_mousepad">Comandament a distància del ratolí</string>
|
||||
<string name="pref_plugin_mousepad_desc">Controla el vostre ratolí de forma remota</string>
|
||||
<string name="pref_plugin_mpris">Comandament a distància multimèdia</string>
|
||||
<string name="pref_plugin_mpris_desc">Controla l\'àudio i el vídeo del vostre telèfon</string>
|
||||
<string name="pref_plugin_ping">Ping</string>
|
||||
<string name="pref_plugin_ping_desc">Envia i rep els pings</string>
|
||||
<string name="pref_plugin_notifications">Sincronitza les notificacions</string>
|
||||
<string name="pref_plugin_notifications_desc">Accedeix a les vostres notificacions des d\'altres dispositius</string>
|
||||
<string name="pref_plugin_sharereceiver">Receptor de compartits</string>
|
||||
<string name="pref_plugin_sharereceiver_desc">Desa els fitxers entrants a l\'emmagatzematge del telèfon</string>
|
||||
<string name="plugin_not_available">Aquesta característica no està disponible en la vostra versió d\'Android</string>
|
||||
<string name="device_list_empty">No hi ha cap dispositiu</string>
|
||||
<string name="ok">D\'acord</string>
|
||||
<string name="cancel">Cancel·la</string>
|
||||
<string name="open_settings">Obre l\'arranjament</string>
|
||||
<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">Obre el comandament a distància</string>
|
||||
<string name="open_mousepad">Obre el control pel plafó tàctil</string>
|
||||
<string name="mousepad_info">Moveu un dit per la pantalla per a moure el cursor del ratolí</string>
|
||||
<string name="category_connected_devices">Dispositius connectats</string>
|
||||
<string name="category_not_paired_devices">Dispositius sense aparellar</string>
|
||||
<string name="category_remembered_devices">Dispositius recordats</string>
|
||||
<string name="plugins_failed_to_load">Els connectors han fallat en carregar-los (puntegeu per a més informació):</string>
|
||||
<string name="device_menu_plugins">Selecció dels connectors</string>
|
||||
<string name="device_menu_unpair">Desparella</string>
|
||||
<string name="device_not_reachable">No s\'ha pogut accedir al dispositiu parell</string>
|
||||
<string name="unknown_device">Dispositiu desconegut</string>
|
||||
<string name="error_not_reachable">No es pot accedir al dispositiu</string>
|
||||
<string name="error_already_requested">Ja s\'ha demanat aparellar</string>
|
||||
<string name="error_already_paired">El dispositiu ja està aparellat</string>
|
||||
<string name="error_could_not_send_package">No s\'ha pogut enviar el paquet</string>
|
||||
<string name="error_timed_out">Ha excedit el temps</string>
|
||||
<string name="error_canceled_by_user">Cancel·lat per l\'usuari</string>
|
||||
<string name="error_canceled_by_other_peer">Cancel·lat per l\'altre parell</string>
|
||||
<string name="error_invalid_key">S\'ha rebut una clau no vàlida</string>
|
||||
<string name="pair_requested">S\'ha demanat aparellar</string>
|
||||
<string name="pairing_request_from">S\'ha demanat aparellar des de %1s</string>
|
||||
<string name="received_url_title">S\'ha rebut un vincle des de %1s</string>
|
||||
<string name="received_url_text">Puntegeu per obrir «%1s»</string>
|
||||
<string name="incoming_file_title">Fitxer entrant des de %1s</string>
|
||||
<string name="incoming_file_text">%1s</string>
|
||||
<string name="received_file_title">Fitxer rebut des de %1s</string>
|
||||
<string name="received_file_text">Puntegeu per obrir «%1s»</string>
|
||||
<string name="tap_to_answer">Puntegeu per a respondre</string>
|
||||
<string name="reconnect">Reconnecta</string>
|
||||
<string name="right_click">Envia un clic del botó dret</string>
|
||||
<string name="middle_click">Envia un clic del botó del mig</string>
|
||||
<string name="show_keyboard">Mostra el teclat</string>
|
||||
<string name="device_not_paired">El dispositiu no està aparellat</string>
|
||||
<string name="request_pairing">Demana aparellar</string>
|
||||
<string name="pairing_accept">Accepta</string>
|
||||
<string name="pairing_reject">Rebutja</string>
|
||||
<string name="device">Dispositiu</string>
|
||||
<string name="pair_device">Dispositiu parell</string>
|
||||
<string name="remote_control">Comandament a distància</string>
|
||||
<string name="settings">Arranjament del KDE Connect</string>
|
||||
<string name="mpris_play">Reprodueix</string>
|
||||
<string name="mpris_previous">Anterior</string>
|
||||
<string name="mpris_rew">Rebobina</string>
|
||||
<string name="mpris_ff">Avanç ràpid</string>
|
||||
<string name="mpris_next">Següent</string>
|
||||
<string name="mpris_volume">Volum</string>
|
||||
<string name="mpris_settings">Arranjament multimèdia</string>
|
||||
<string name="mpris_time_settings_title">Interval de temps</string>
|
||||
<string name="mpris_time_settings_summary">Ajusta el temps per avançar o rebobinar un fitxer multimèdia.</string>
|
||||
<string name="share_to">Comparteix amb...</string>
|
||||
<string name="protocol_version_older">Aquest dispositiu usa una versió antiga del protocol</string>
|
||||
<string name="protocol_version_newer">Aquest dispositiu usa una versió nova del protocol</string>
|
||||
<string name="general_settings">Arranjament general</string>
|
||||
<string name="plugin_settings">Arranjament</string>
|
||||
<string name="device_name">Nom del dispositiu</string>
|
||||
<string name="device_name_preference_summary">%s</string>
|
||||
<string name="invalid_device_name">El nom del dispositiu no és vàlid</string>
|
||||
<string name="shareplugin_text_saved">S\'ha rebut text i s\'ha desat al porta-retalls</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="sftp_internal_storage">Emmagatzematge intern</string>
|
||||
<string name="sftp_all_files">Tots els fitxers</string>
|
||||
<string name="sftp_sdcard_num">Targeta SD %d</string>
|
||||
<string name="sftp_sdcard">Targeta SD</string>
|
||||
<string name="sftp_readonly">(només de lectura)</string>
|
||||
<string name="sftp_camera">Imatges de la càmera</string>
|
||||
<string-array name="mpris_time_entries">
|
||||
<item>10 segons</item>
|
||||
<item>20 segons</item>
|
||||
<item>30 segons</item>
|
||||
<item>1 minut</item>
|
||||
<item>2 minuts</item>
|
||||
</string-array>
|
||||
</resources>
|
@@ -1,30 +1,101 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<resources>
|
||||
<string name="pref_plugin_telephony">Upozornění telefonie</string>
|
||||
<string name="pref_plugin_telephony_desc">Posílat upozornění na SMS a hovory</string>
|
||||
<string name="pref_plugin_battery">Hlášení baterie</string>
|
||||
<string name="pref_plugin_battery_desc">Periodicky hlásit stav baterky</string>
|
||||
<string name="pref_plugin_sftp">Přístup k souborovému systému</string>
|
||||
<string name="pref_plugin_sftp_desc">Umožní vám vzdáleně prohlížet souborový systém telefonu</string>
|
||||
<string name="pref_plugin_clipboard">Synchronizace schránky</string>
|
||||
<string name="pref_plugin_clipboard_desc">Sdílet obsah schránky</string>
|
||||
<string name="pref_plugin_mousepad">Vzdálené ovládání myši</string>
|
||||
<string name="pref_plugin_mousepad_desc">Ovládejte svou myš vzdáleně</string>
|
||||
<string name="pref_plugin_mpris">Vzdálené ovládání multimédií</string>
|
||||
<string name="pref_plugin_mpris_desc">Ovládejte audio/video z vašeho telefonu</string>
|
||||
<string name="pref_plugin_ping">Ping</string>
|
||||
<string name="pref_plugin_ping_desc">Posílat a přijímat ping</string>
|
||||
<string name="pref_plugin_notifications">Synchronizace upozornění</string>
|
||||
<string name="pref_plugin_notifications_desc">Zpřístupněte si upozornění z jiných zařízení</string>
|
||||
<string name="pref_plugin_sharereceiver">Sdílet příjemce</string>
|
||||
<string name="pref_plugin_sharereceiver_desc">Ukládat příchozí soubory do úložiště telefonu</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>
|
||||
<string name="ok">OK</string>
|
||||
<string name="cancel">Zrušit</string>
|
||||
<string name="open_settings">Otevřít nastavení</string>
|
||||
<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">Otevřít vzdálené ovládání</string>
|
||||
<string name="open_mousepad">Otevřít dotykové ovládání</string>
|
||||
<string name="mousepad_info">Pohybujte prstem po monitoru pro pohybování kurzorem myši</string>
|
||||
<string name="category_connected_devices">Připojená zařízení</string>
|
||||
<string name="category_not_paired_devices">Nespárovaná zařízení</string>
|
||||
<string name="category_remembered_devices">Zapamatovaná zařízení</string>
|
||||
<string name="plugins_failed_to_load">Moduly nebyly načteny (ťukněte pro více informací):</string>
|
||||
<string name="device_menu_plugins">Vyberte moduly</string>
|
||||
<string name="device_menu_unpair">Zrušit párování</string>
|
||||
<string name="device_not_reachable">Spárované zařízení je nedostupné</string>
|
||||
<string name="unknown_device">Neznámé zařízení</string>
|
||||
<string name="error_not_reachable">Zařízení je nedostupné</string>
|
||||
<string name="error_already_requested">Párování již bylo vyžádáno</string>
|
||||
<string name="error_already_paired">Zařízení je již spárované</string>
|
||||
<string name="error_could_not_send_package">Balíček nelze poslat</string>
|
||||
<string name="error_timed_out">Čas vypršel</string>
|
||||
<string name="error_canceled_by_user">Přerušeno uživatelem</string>
|
||||
<string name="error_canceled_by_other_peer">Přerušeno druhým uživatelem</string>
|
||||
<string name="error_invalid_key">Byl přijat neplatný klíč</string>
|
||||
<string name="pair_requested">Bylo vyžádáno párování</string>
|
||||
<string name="pairing_request_from">Požadavek o párování z %1s</string>
|
||||
<string name="received_url_title">Přijat odkaz od %1s</string>
|
||||
<string name="received_url_text">Ťukněte pro otevření \'%1s\'</string>
|
||||
<string name="incoming_file_title">Příchozí soubor od %1s</string>
|
||||
<string name="incoming_file_text">%1s</string>
|
||||
<string name="received_file_title">Přijat soubor od %1s</string>
|
||||
<string name="received_file_text">Ťukněte pro otevření \'%1s\'</string>
|
||||
<string name="tap_to_answer">Ťukněte pro odpovězení</string>
|
||||
<string name="reconnect">Znovu připojit</string>
|
||||
<string name="right_click">Poslat kliknutí pravým tlačítkem</string>
|
||||
<string name="middle_click">Poslat kliknutí prostředním tlačítkem</string>
|
||||
<string name="show_keyboard">Zobrazit klávesnici</string>
|
||||
<string name="device_not_paired">Zařízení není spárované</string>
|
||||
<string name="request_pairing">Vyžádat párování</string>
|
||||
<string name="pairing_accept">Přijmout</string>
|
||||
<string name="pairing_reject">Odmítnout</string>
|
||||
<string name="device">Zařízení</string>
|
||||
<string name="pair_device">Spárovat zařízení</string>
|
||||
<string name="remote_control">Vzdálené ovládání</string>
|
||||
<string name="settings">Nastavení KDE Connect</string>
|
||||
<string name="mpris_play">Přehrát</string>
|
||||
<string name="mpris_previous">Předchozí</string>
|
||||
<string name="mpris_rew">Přetočit zpět</string>
|
||||
<string name="mpris_ff">Rychle vpřed</string>
|
||||
<string name="mpris_next">Následující</string>
|
||||
<string name="mpris_volume">Hlasitost</string>
|
||||
<string name="mpris_settings">Nastavení multimédií</string>
|
||||
<string name="mpris_time_settings_title">Časový interval</string>
|
||||
<string name="mpris_time_settings_summary">Upravit čas pro rychlý posun multimediálním souborem vpřed a zpět.</string>
|
||||
<string name="share_to">Sdílet s...</string>
|
||||
<string name="protocol_version_older">Toto zařízení používá starou verzi protokolu</string>
|
||||
<string name="protocol_version_newer">Toto zařízení používá novější verzi protokolu</string>
|
||||
<string name="general_settings">Obecná nastavení</string>
|
||||
<string name="plugin_settings">Nastavení</string>
|
||||
<string name="device_name">Název zařízení</string>
|
||||
<string name="device_name_preference_summary">%s</string>
|
||||
<string name="invalid_device_name">Neplatný název zařízení</string>
|
||||
<string name="shareplugin_text_saved">Přijatý text byl uložen do schránky</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="sftp_internal_storage">Interní úložiště</string>
|
||||
<string name="sftp_all_files">Všechny soubory</string>
|
||||
<string name="sftp_sdcard_num">SD karta %d</string>
|
||||
<string name="sftp_sdcard">SD karta</string>
|
||||
<string name="sftp_readonly">(pouze ke čtení)</string>
|
||||
<string name="sftp_camera">Obrázky z fotoaparátu</string>
|
||||
<string-array name="mpris_time_entries">
|
||||
<item>10 sekund</item>
|
||||
<item>20 sekund</item>
|
||||
<item>30 sekund</item>
|
||||
<item>1 minuta</item>
|
||||
<item>2 minuty</item>
|
||||
</string-array>
|
||||
</resources>
|
||||
|
92
src/main/res/values-da/strings.xml
Normal file
@@ -0,0 +1,92 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<resources>
|
||||
<string name="pref_plugin_telephony">Telefonibekendtgørelse</string>
|
||||
<string name="pref_plugin_telephony_desc">Send bekendtgørelser om SMS\'er og opkald</string>
|
||||
<string name="pref_plugin_battery">Batterirapport</string>
|
||||
<string name="pref_plugin_battery_desc">Rapportér batteristatus periodisk</string>
|
||||
<string name="pref_plugin_sftp">Filsystem-expose</string>
|
||||
<string name="pref_plugin_sftp_desc">Muliggør at gennemsøge telefonens filsystem eksternt</string>
|
||||
<string name="pref_plugin_clipboard">Synk. af udklipsholder</string>
|
||||
<string name="pref_plugin_clipboard_desc">Del indholdet af udklipsholderen</string>
|
||||
<string name="pref_plugin_mousepad">Fjernbetjening af mus</string>
|
||||
<string name="pref_plugin_mousepad_desc">Styrer din mus på afstand</string>
|
||||
<string name="pref_plugin_mpris">Fjernbetjening af multimedie</string>
|
||||
<string name="pref_plugin_mpris_desc">Styr lyd og video fra din telefon</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>
|
||||
<string name="pref_plugin_notifications_desc">Tilgå dine bekendtgørelser fra andre enheder</string>
|
||||
<string name="pref_plugin_sharereceiver">Del modtager</string>
|
||||
<string name="pref_plugin_sharereceiver_desc">Gem indkommende filer til telefonens lager</string>
|
||||
<string name="plugin_not_available">Denne funktion er ikke tilgængelig i din Android-version</string>
|
||||
<string name="device_list_empty">Ingen enheder</string>
|
||||
<string name="ok">O.k.</string>
|
||||
<string name="cancel">Annullér</string>
|
||||
<string name="open_settings">Åbn indstillinger</string>
|
||||
<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">Åbn fjernbetjening</string>
|
||||
<string name="open_mousepad">Åbn touchpad-kontrol</string>
|
||||
<string name="mousepad_info">Bevæg en finger på skærmen for at flytte musemarkøren</string>
|
||||
<string name="category_connected_devices">Forbundne enheder</string>
|
||||
<string name="category_not_paired_devices">Ikke parrede enheder</string>
|
||||
<string name="category_remembered_devices">Huskede enheder</string>
|
||||
<string name="plugins_failed_to_load">Plugins kunne ikke indlæses (tap for mere info):</string>
|
||||
<string name="device_menu_plugins">Vælg plugins</string>
|
||||
<string name="device_menu_unpair">Fjern parring</string>
|
||||
<string name="device_not_reachable">Den parrede enhed kan ikke tilgås</string>
|
||||
<string name="unknown_device">Ukendt enhed</string>
|
||||
<string name="error_not_reachable">Enheden kan ikke nås</string>
|
||||
<string name="error_already_requested">Allerede anmodet om parring</string>
|
||||
<string name="error_already_paired">Enhed allerede parret</string>
|
||||
<string name="error_could_not_send_package">Kunne ikke sende pakke</string>
|
||||
<string name="error_timed_out">Tidsudløb</string>
|
||||
<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="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>
|
||||
<string name="received_url_text">Tap for at åbne \"%1s\"</string>
|
||||
<string name="incoming_file_title">Indkommende fil fra %1s</string>
|
||||
<string name="incoming_file_text">%1s</string>
|
||||
<string name="received_file_title">Modtog fil fra %1s</string>
|
||||
<string name="received_file_text">Tap for at åbne \"%1s\"</string>
|
||||
<string name="tap_to_answer">Tap for at svare</string>
|
||||
<string name="reconnect">Forbind igen</string>
|
||||
<string name="right_click">Send højreklik</string>
|
||||
<string name="middle_click">Send midterklik</string>
|
||||
<string name="show_keyboard">Vis tastatur</string>
|
||||
<string name="device_not_paired">Enhed ikke parret</string>
|
||||
<string name="request_pairing">Anmod om parring</string>
|
||||
<string name="pairing_accept">Acceptér</string>
|
||||
<string name="pairing_reject">Afvis</string>
|
||||
<string name="device">Enhed</string>
|
||||
<string name="pair_device">Par med enhed</string>
|
||||
<string name="remote_control">Fjernbetjening</string>
|
||||
<string name="settings">Indstilling af KDE Connect</string>
|
||||
<string name="mpris_play">Afspil</string>
|
||||
<string name="mpris_previous">Forrige</string>
|
||||
<string name="mpris_rew">Spol tilbage</string>
|
||||
<string name="mpris_ff">Spol frem</string>
|
||||
<string name="mpris_next">Næste</string>
|
||||
<string name="mpris_volume">Lydstyrke</string>
|
||||
<string name="mpris_settings">Fjernbetjening af multimedie</string>
|
||||
<string name="share_to">Del på...</string>
|
||||
<string name="protocol_version_older">Denne enhed bruger en gammel protokolversion</string>
|
||||
<string name="protocol_version_newer">Denne enhed bruger en nyere protokolversion</string>
|
||||
<string name="general_settings">Generelle indstillinger</string>
|
||||
<string name="plugin_settings">Generelle indstillinger</string>
|
||||
<string name="device_name">Enhedsnavn</string>
|
||||
<string name="device_name_preference_summary">%s</string>
|
||||
<string name="invalid_device_name">Ugyldigt enhedsnavn</string>
|
||||
<string name="shareplugin_text_saved">Modtog tekst, gemt til udklipsholder</string>
|
||||
<string name="share_notification_preference">Synk. af bekendtgørelser</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>
|
||||
</string-array>
|
||||
</resources>
|
@@ -4,24 +4,34 @@
|
||||
<string name="pref_plugin_telephony_desc">Benachrichtigungen über SMS und Anrufe senden</string>
|
||||
<string name="pref_plugin_battery">Akkubericht</string>
|
||||
<string name="pref_plugin_battery_desc">Akkustatus periodisch berichten</string>
|
||||
<string name="pref_plugin_sftp">Dateisystem zeigen</string>
|
||||
<string name="pref_plugin_sftp_desc">Erlaubt das Browsen des Dateisystems auf dem entfernten Handy</string>
|
||||
<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">Maus-Fernbedienung</string>
|
||||
<string name="pref_plugin_mpris">Multimedia-Fernbedienungen</string>
|
||||
<string name="pref_plugin_mpris_desc">Audio und Video mit Ihrem Telefon steuern</string>
|
||||
<string name="pref_plugin_ping">Ping</string>
|
||||
<string name="pref_plugin_ping_desc">Senden und Empfangen von Pings</string>
|
||||
<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_sharereceiver_desc">Eingehende Dateien auf dem Telefonspeicher ablegen</string>
|
||||
<string name="plugin_not_available">Diese Funktion ist in Ihrer Android-Version nicht verfügbar</string>
|
||||
<string name="device_list_empty">Keine Geräte</string>
|
||||
<string name="ok">OK</string>
|
||||
<string name="cancel">Abbrechen</string>
|
||||
<string name="open_settings">Einstellungen öffnen</string>
|
||||
<string name="no_permissions">Sie müssen die Erlaubnis zum Zugriff auf Benachrichtigungen erteilen</string>
|
||||
<string name="send_ping">Ping senden</string>
|
||||
<string name="open_mpris_controls">Fernbedienung öffnen</string>
|
||||
<string name="open_mousepad">Touchpad-Steuerung öffnen</string>
|
||||
<string name="category_connected_devices">Verbundene Geräte</string>
|
||||
<string name="category_not_paired_devices">Keine angeschlossenen Geräte</string>
|
||||
<string name="category_remembered_devices">Gemerkte Geräte</string>
|
||||
<string name="plugins_failed_to_load">Laden der Module fehlgeschlagen, tippen Sie für weitere Details:</string>
|
||||
<string name="device_menu_plugins">Module auswählen</string>
|
||||
<string name="device_menu_unpair">Verbindung trennen</string>
|
||||
<string name="device_not_reachable">Das angegeben Gerät ist nicht erreichbar</string>
|
||||
<string name="unknown_device">Unbekanntes Gerät</string>
|
||||
<string name="error_not_reachable">Das Gerät ist nicht erreichbar</string>
|
||||
<string name="error_already_requested">Die Verbindung wurde bereits angefragt</string>
|
||||
@@ -33,7 +43,15 @@
|
||||
<string name="error_invalid_key">Ungültiger Schlüssel empfangen</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="incoming_file_title">Eingehende Datei von %1s</string>
|
||||
<string name="incoming_file_text">%1s</string>
|
||||
<string name="received_file_title">Datei von %1s erhalten</string>
|
||||
<string name="tap_to_answer">Tippen zum Antworten</string>
|
||||
<string name="reconnect">Erneut verbinden</string>
|
||||
<string name="right_click">Rechtsklick senden</string>
|
||||
<string name="middle_click">Mittelklick senden</string>
|
||||
<string name="show_keyboard">Tastatur anzeigen</string>
|
||||
<string name="device_not_paired">Das Gerät ist nicht verbunden</string>
|
||||
<string name="request_pairing">Verbindung angefordert</string>
|
||||
<string name="pairing_accept">Annehmen</string>
|
||||
@@ -48,10 +66,29 @@
|
||||
<string name="mpris_ff">Vorlauf</string>
|
||||
<string name="mpris_next">Weiter</string>
|
||||
<string name="mpris_volume">Lautstärke</string>
|
||||
<string name="mpris_settings">Multimedia-Einstellungen</string>
|
||||
<string name="share_to">Freigeben für ...</string>
|
||||
<string name="protocol_version_older">Dieses Gerät verwendet ein alte Protokollversion</string>
|
||||
<string name="protocol_version_newer">Dieses Gerät verwendet ein neuere Protokollversion</string>
|
||||
<string name="general_settings">Allgemeine Einstellungen</string>
|
||||
<string name="plugin_settings">Einstellungen</string>
|
||||
<string name="device_name">Gerätename</string>
|
||||
<string name="device_name_preference_summary">%s</string>
|
||||
<string name="invalid_device_name">Ungültiger Gerätename</string>
|
||||
<string name="shareplugin_text_saved">Text empfangen und in der Zwischenablage gespeichert</string>
|
||||
<string name="share_notification_preference">Benachrichtigungs-Abgleich</string>
|
||||
<string name="share_notification_preference_summary">Beim Empfang einer Datei vibrieren und einen Sound abspielen</string>
|
||||
<string name="sftp_internal_storage">Interner Speicher</string>
|
||||
<string name="sftp_all_files">Alle Dateien</string>
|
||||
<string name="sftp_sdcard_num">SD-Karte %d</string>
|
||||
<string name="sftp_sdcard">SD-Karte</string>
|
||||
<string name="sftp_readonly">(Nur lesen)</string>
|
||||
<string name="sftp_camera">Kamerabilder</string>
|
||||
<string-array name="mpris_time_entries">
|
||||
<item>10 Sekunden</item>
|
||||
<item>20 Sekunden</item>
|
||||
<item>30 Sekunden</item>
|
||||
<item>1 Minute</item>
|
||||
<item>2 Minuten</item>
|
||||
</string-array>
|
||||
</resources>
|
||||
|
@@ -4,15 +4,21 @@
|
||||
<string name="pref_plugin_telephony_desc">Enviar notificaciones de SMS y llamadas</string>
|
||||
<string name="pref_plugin_battery">Informe de la batería</string>
|
||||
<string name="pref_plugin_battery_desc">Informar periódicamente del estado de la batería</string>
|
||||
<string name="pref_plugin_sftp">Revelar el sistema de archivos</string>
|
||||
<string name="pref_plugin_sftp_desc">Permite examinar de forma remota el sistema de archivos del teléfono</string>
|
||||
<string name="pref_plugin_clipboard">Sincronización del portapapeles</string>
|
||||
<string name="pref_plugin_clipboard_desc">Compartir el contenido del portapapeles</string>
|
||||
<string name="pref_plugin_mousepad">Control remoto del ratón</string>
|
||||
<string name="pref_plugin_mousepad_desc">Controlar su ratón remotamente</string>
|
||||
<string name="pref_plugin_mpris">Controles remotos multimedia</string>
|
||||
<string name="pref_plugin_mpris_desc">Controlar audio y vídeo desde el teléfono</string>
|
||||
<string name="pref_plugin_ping">Ping</string>
|
||||
<string name="pref_plugin_ping_desc">Enviar y recibir pings</string>
|
||||
<string name="pref_plugin_notifications">Sincronizar notificaciones</string>
|
||||
<string name="pref_plugin_notifications_desc">Acceder a las notificaciones desde otros dispositivos</string>
|
||||
<string name="plugin_not_available">Esta función no está disponible en su versión de Android</string>
|
||||
<string name="pref_plugin_sharereceiver">Compartir receptor</string>
|
||||
<string name="pref_plugin_sharereceiver_desc">Guardar archivos entrantes en el almacenamiento del teléfono</string>
|
||||
<string name="plugin_not_available">Esta funcionalidad no está disponible en su versión de Android</string>
|
||||
<string name="device_list_empty">Ningún dispositivo</string>
|
||||
<string name="ok">Aceptar</string>
|
||||
<string name="cancel">Cancelar</string>
|
||||
@@ -20,12 +26,15 @@
|
||||
<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">Abrir control remoto</string>
|
||||
<string name="open_mousepad">Abrir control del panel táctil</string>
|
||||
<string name="mousepad_info">Mueva un dedo sobre la pantalla para mover el cursor del ratón</string>
|
||||
<string name="category_connected_devices">Dispositivos conectados</string>
|
||||
<string name="category_not_paired_devices">Dispositivos no vinculados</string>
|
||||
<string name="category_remembered_devices">Dispositivos recordados</string>
|
||||
<string name="plugins_failed_to_load">Complementos cuya carga ha fallado (toque para más información):</string>
|
||||
<string name="device_menu_plugins">Seleccionar complementos</string>
|
||||
<string name="device_menu_unpair">Desvincular</string>
|
||||
<string name="device_not_reachable">No se encuentra el dispositivo aparejado</string>
|
||||
<string name="unknown_device">Dispositivo desconocido</string>
|
||||
<string name="error_not_reachable">No se encuentra el dispositivo</string>
|
||||
<string name="error_already_requested">Ya ha solicitado vincularse</string>
|
||||
@@ -37,8 +46,17 @@
|
||||
<string name="error_invalid_key">Se ha recibido una clave no valida</string>
|
||||
<string name="pair_requested">Vinculación solicitada</string>
|
||||
<string name="pairing_request_from">Solicitud de vinculación de %1s</string>
|
||||
<string name="received_url_title">Enlace recibido desde %1s</string>
|
||||
<string name="received_url_text">Pulse para abrir «%1s»</string>
|
||||
<string name="incoming_file_title">Archivo entrante desde %1s</string>
|
||||
<string name="incoming_file_text">%1s</string>
|
||||
<string name="received_file_title">Archivo recibido desde %1s</string>
|
||||
<string name="received_file_text">Pulse para abrir «%1s»</string>
|
||||
<string name="tap_to_answer">Toque para responder</string>
|
||||
<string name="reconnect">Reconectar</string>
|
||||
<string name="right_click">Enviar clic derecho</string>
|
||||
<string name="middle_click">Enviar clic del botón central</string>
|
||||
<string name="show_keyboard">Mostrar teclado</string>
|
||||
<string name="device_not_paired">Dispositivo no vinculado</string>
|
||||
<string name="request_pairing">Solicitar vinculación</string>
|
||||
<string name="pairing_accept">Aceptar</string>
|
||||
@@ -49,12 +67,29 @@
|
||||
<string name="settings">Preferencias de KDE Connect</string>
|
||||
<string name="mpris_play">Reproducir</string>
|
||||
<string name="mpris_previous">Anterior</string>
|
||||
<string name="mpris_rew">Rebobinar</string>
|
||||
<string name="mpris_ff">Avance rápido</string>
|
||||
<string name="mpris_next">Siguiente</string>
|
||||
<string name="mpris_volume">Volumen</string>
|
||||
<string name="mpris_settings">Preferencias multimedia</string>
|
||||
<string name="mpris_time_settings_title">Intervalo de tiempo</string>
|
||||
<string name="mpris_time_settings_summary">Ajustar el tiempo a avanzar o rebobinar un archivo multimedia.</string>
|
||||
<string name="share_to">Compartir con...</string>
|
||||
<string name="protocol_version_older">Este dispositivo usa una versión antigua del protocolo</string>
|
||||
<string name="protocol_version_newer">Este dispositivo usa una versión más reciente del protocolo</string>
|
||||
<string name="general_settings">Abrir preferencias</string>
|
||||
<string name="device_name">Dispositivo no vinculado</string>
|
||||
<string name="invalid_device_name">Se ha recibido una clave no valida</string>
|
||||
<string name="general_settings">Preferencias generales</string>
|
||||
<string name="plugin_settings">Preferencias</string>
|
||||
<string name="device_name">Nombre de dispositivo</string>
|
||||
<string name="device_name_preference_summary">%s</string>
|
||||
<string name="invalid_device_name">Nombre de dispositivo no válido</string>
|
||||
<string name="shareplugin_text_saved">Texto recibido y guardado en el portapapeles</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-array name="mpris_time_entries">
|
||||
<item>10 segundos</item>
|
||||
<item>20 segundos</item>
|
||||
<item>30 segundos</item>
|
||||
<item>1 minuto</item>
|
||||
<item>2 minutos</item>
|
||||
</string-array>
|
||||
</resources>
|
||||
|