Compare commits

...

22 Commits

Author SHA1 Message Date
chteufleur 137f024117 Add send trail over XMPP (Should work with q serveur proxy). 2018-10-06 11:29:04 +02:00
chteufleur 371f5aa1cb Clean code. 2018-10-06 09:48:44 +02:00
chteufleur 27f506c253 Remove "otherJid" when receiving unavailable presence. 2018-10-05 19:34:16 +02:00
chteufleur ebe4208502 Simulate back button on receiving presence of other device. 2018-10-05 18:14:50 +02:00
chteufleur 192838b585 Fix XMPP start/stop infinite loop. 2018-10-05 17:47:35 +02:00
chteufleur d253dbd765 Cleanning code. 2018-10-05 16:08:55 +02:00
chteufleur 0176f37d01 Move trace management into ServiceTrackingDog. 2018-10-05 15:20:22 +02:00
chteufleur 25504418d3 Integration of ServiceXmpp into ServiceTrackingDog. 2018-10-05 12:12:25 +02:00
chteufleur 83342b5be9 Add ServiceTrackingDog for better services management. 2018-10-05 11:28:38 +02:00
chteufleur 1361473eee Add menu to connect on XMPP. 2018-10-04 18:05:05 +02:00
chteufleur 5246ab3595 Activate XMPP location received only on traceur activated. 2018-10-04 17:15:57 +02:00
chteufleur aaffa44e7f Keep screen ON on other activities. 2018-10-04 17:10:12 +02:00
chteufleur c25fb43434 Reorganization of GPX code. 2018-10-04 16:37:54 +02:00
chteufleur 2dd8f75822 Reorganization of ServiceGps code. 2018-10-04 16:30:13 +02:00
chteufleur b856f3f4e1 Reorganization of ServiceXmpp code. 2018-10-04 16:09:17 +02:00
chteufleur f040aaa514 Reorganization of MainActivity code. 2018-10-04 16:06:46 +02:00
chteufleur 35d9b8ccfb Send trail over XMPP. 2018-10-03 17:50:48 +02:00
chteufleur f1ad139832 Add object location received on XMPP. 2018-10-03 15:59:38 +02:00
chteufleur 367c72bf8c Receive start, stop and location on XMPP. 2018-10-03 14:32:50 +02:00
chteufleur e41c3e9948 Anonymous XMPP connection + preparing Ad-Hoc command 2018-10-03 11:41:01 +02:00
chteufleur fd2947d9b8 Add menu to enable/disable vibration on approaching. 2018-09-28 16:01:31 +02:00
chteufleur afbd353f71 Vibration when approaching object. 2018-09-27 18:14:35 +02:00
43 changed files with 2138 additions and 437 deletions

View File

@ -0,0 +1,11 @@
<component name="libraryTable">
<library name="Gradle: com.google.zxing:core:3.2.1@jar">
<CLASSES>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/com.google.zxing/core/3.2.1/2287494d4f5f9f3a9a2bb6980e3f32053721b315/core-3.2.1.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/com.google.zxing/core/3.2.1/e88788f756edecae963417e07b690e88aaaa7c15/core-3.2.1-sources.jar!/" />
</SOURCES>
</library>
</component>

View File

@ -0,0 +1,11 @@
<component name="libraryTable">
<library name="Gradle: de.measite.minidns:minidns-core:0.2.4@jar">
<CLASSES>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/de.measite.minidns/minidns-core/0.2.4/e4a6561fade362814e336c9402b2c4341b6a5189/minidns-core-0.2.4.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/de.measite.minidns/minidns-core/0.2.4/2bfa0923df30a7254ea0110329c9eebce14d507f/minidns-core-0.2.4-sources.jar!/" />
</SOURCES>
</library>
</component>

View File

@ -0,0 +1,11 @@
<component name="libraryTable">
<library name="Gradle: de.measite.minidns:minidns-dnssec:0.2.4@jar">
<CLASSES>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/de.measite.minidns/minidns-dnssec/0.2.4/a379c5dc82d6e9d5d6c3fa3c56a048bfbb89d3b6/minidns-dnssec-0.2.4.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/de.measite.minidns/minidns-dnssec/0.2.4/84d0c25d677b10ff5111a669b05ec678c80b3ec8/minidns-dnssec-0.2.4-sources.jar!/" />
</SOURCES>
</library>
</component>

View File

@ -0,0 +1,11 @@
<component name="libraryTable">
<library name="Gradle: de.measite.minidns:minidns-hla:0.2.4@jar">
<CLASSES>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/de.measite.minidns/minidns-hla/0.2.4/c4b9a2cf4da635c38ebf7982a276a05850eaaf98/minidns-hla-0.2.4.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/de.measite.minidns/minidns-hla/0.2.4/19b7f2edf7b15f619261e9475520ad9c96dcbaa4/minidns-hla-0.2.4-sources.jar!/" />
</SOURCES>
</library>
</component>

View File

@ -0,0 +1,11 @@
<component name="libraryTable">
<library name="Gradle: de.measite.minidns:minidns-iterative-resolver:0.2.4@jar">
<CLASSES>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/de.measite.minidns/minidns-iterative-resolver/0.2.4/bd9864adf15337f87d4ed4b46fd50f395f1cc721/minidns-iterative-resolver-0.2.4.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/de.measite.minidns/minidns-iterative-resolver/0.2.4/9874a559dda1d698f745bee9885c0be8ada3638d/minidns-iterative-resolver-0.2.4-sources.jar!/" />
</SOURCES>
</library>
</component>

View File

@ -0,0 +1,10 @@
<component name="libraryTable">
<library name="Gradle: me.dm7.barcodescanner:core-1.9">
<CLASSES>
<root url="jar://$USER_HOME$/.gradle/caches/transforms-1/files-1.1/core-1.9.aar/35f5bbf1c3c89e4cf8f6be1211d87d50/jars/classes.jar!/" />
<root url="file://$USER_HOME$/.gradle/caches/transforms-1/files-1.1/core-1.9.aar/35f5bbf1c3c89e4cf8f6be1211d87d50/res" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</component>

View File

@ -0,0 +1,10 @@
<component name="libraryTable">
<library name="Gradle: me.dm7.barcodescanner:zxing-1.9">
<CLASSES>
<root url="file://$USER_HOME$/.gradle/caches/transforms-1/files-1.1/zxing-1.9.aar/4fe25337b4e8593ab11fc6034f238ff3/res" />
<root url="jar://$USER_HOME$/.gradle/caches/transforms-1/files-1.1/zxing-1.9.aar/4fe25337b4e8593ab11fc6034f238ff3/jars/classes.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</component>

View File

@ -0,0 +1,11 @@
<component name="libraryTable">
<library name="Gradle: org.igniterealtime.smack:smack-android:4.2.0@jar">
<CLASSES>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.igniterealtime.smack/smack-android/4.2.0/1fba3d428a9118497469dd723ae60ab9f44e19ab/smack-android-4.2.0.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.igniterealtime.smack/smack-android/4.2.0/85500dc0a7abbcce1313431953c47d8bf4728559/smack-android-4.2.0-sources.jar!/" />
</SOURCES>
</library>
</component>

View File

@ -0,0 +1,11 @@
<component name="libraryTable">
<library name="Gradle: org.igniterealtime.smack:smack-android-extensions:4.2.0@jar">
<CLASSES>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.igniterealtime.smack/smack-android-extensions/4.2.0/ed0c66a3b414382155b00d08652145ceaed23856/smack-android-extensions-4.2.0.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.igniterealtime.smack/smack-android-extensions/4.2.0/bafc8db5015e078bd28c7c8531eabc4a1af900d1/smack-android-extensions-4.2.0-sources.jar!/" />
</SOURCES>
</library>
</component>

View File

@ -0,0 +1,11 @@
<component name="libraryTable">
<library name="Gradle: org.igniterealtime.smack:smack-core:4.2.0@jar">
<CLASSES>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.igniterealtime.smack/smack-core/4.2.0/b460b28484d6315dfa158af0bb9a050c92ea106f/smack-core-4.2.0.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.igniterealtime.smack/smack-core/4.2.0/2b049a427e166f79c8b6063a54b9d34f2c376e48/smack-core-4.2.0-sources.jar!/" />
</SOURCES>
</library>
</component>

View File

@ -0,0 +1,11 @@
<component name="libraryTable">
<library name="Gradle: org.igniterealtime.smack:smack-extensions:4.2.0@jar">
<CLASSES>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.igniterealtime.smack/smack-extensions/4.2.0/3bffdc845de26ab601ac9a92e53c02f8676609fe/smack-extensions-4.2.0.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.igniterealtime.smack/smack-extensions/4.2.0/285595c8d6ced29196ea5552148836e69e8d07cc/smack-extensions-4.2.0-sources.jar!/" />
</SOURCES>
</library>
</component>

View File

@ -0,0 +1,11 @@
<component name="libraryTable">
<library name="Gradle: org.igniterealtime.smack:smack-im:4.2.0@jar">
<CLASSES>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.igniterealtime.smack/smack-im/4.2.0/c1805ee14fe07ac65683e4b22d796d30a4171fd9/smack-im-4.2.0.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.igniterealtime.smack/smack-im/4.2.0/781f1a714249b1330d218b242127a8bdba722839/smack-im-4.2.0-sources.jar!/" />
</SOURCES>
</library>
</component>

View File

@ -0,0 +1,11 @@
<component name="libraryTable">
<library name="Gradle: org.igniterealtime.smack:smack-resolver-minidns:4.2.0@jar">
<CLASSES>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.igniterealtime.smack/smack-resolver-minidns/4.2.0/f455576bef17e16ff5627fee48586aefe3855026/smack-resolver-minidns-4.2.0.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.igniterealtime.smack/smack-resolver-minidns/4.2.0/d00c3103c0f479f85e3ec9b0a4685625097b612b/smack-resolver-minidns-4.2.0-sources.jar!/" />
</SOURCES>
</library>
</component>

View File

@ -0,0 +1,11 @@
<component name="libraryTable">
<library name="Gradle: org.igniterealtime.smack:smack-sasl-provided:4.2.0@jar">
<CLASSES>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.igniterealtime.smack/smack-sasl-provided/4.2.0/dd5420f029cd3251fd8dfaa3de93ef8a8a607fc8/smack-sasl-provided-4.2.0.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.igniterealtime.smack/smack-sasl-provided/4.2.0/e5938aef4210cab2b68ef9aa1283fc869cea8537/smack-sasl-provided-4.2.0-sources.jar!/" />
</SOURCES>
</library>
</component>

View File

@ -0,0 +1,11 @@
<component name="libraryTable">
<library name="Gradle: org.igniterealtime.smack:smack-tcp:4.2.0@jar">
<CLASSES>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.igniterealtime.smack/smack-tcp/4.2.0/1ebbf8b432a4d154171141dcd5aef800e43ab1cd/smack-tcp-4.2.0.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.igniterealtime.smack/smack-tcp/4.2.0/84567022565b936ed9d65eb0dceccc8c0e9d6eb3/smack-tcp-4.2.0-sources.jar!/" />
</SOURCES>
</library>
</component>

View File

@ -0,0 +1,11 @@
<component name="libraryTable">
<library name="Gradle: org.jxmpp:jxmpp-core:0.5.0@jar">
<CLASSES>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jxmpp/jxmpp-core/0.5.0/f87f6947d74e7d126965b8a58a5472bbbea5f956/jxmpp-core-0.5.0.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jxmpp/jxmpp-core/0.5.0/afd7bb9e2de02cd1fd267bbe3b360c1769de726f/jxmpp-core-0.5.0-sources.jar!/" />
</SOURCES>
</library>
</component>

View File

@ -0,0 +1,11 @@
<component name="libraryTable">
<library name="Gradle: org.jxmpp:jxmpp-jid:0.5.0@jar">
<CLASSES>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jxmpp/jxmpp-jid/0.5.0/eb66b23d633f6a8c01526a78507dac80afef239c/jxmpp-jid-0.5.0.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jxmpp/jxmpp-jid/0.5.0/cd9e5d82c11aebf948aed1945c98b7196748b294/jxmpp-jid-0.5.0-sources.jar!/" />
</SOURCES>
</library>
</component>

View File

@ -0,0 +1,11 @@
<component name="libraryTable">
<library name="Gradle: org.jxmpp:jxmpp-util-cache:0.5.0@jar">
<CLASSES>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jxmpp/jxmpp-util-cache/0.5.0/32752e1fdf24320a2363d9b92504abf05f9b6548/jxmpp-util-cache-0.5.0.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jxmpp/jxmpp-util-cache/0.5.0/dc6cdd925ebeaba7593aa80e377738c431a6f02c/jxmpp-util-cache-0.5.0-sources.jar!/" />
</SOURCES>
</library>
</component>

View File

@ -0,0 +1,11 @@
<component name="libraryTable">
<library name="Gradle: xpp3:xpp3:1.1.4c@jar">
<CLASSES>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/xpp3/xpp3/1.1.4c/9b988ea84b9e4e9f1874e390ce099b8ac12cfff5/xpp3-1.1.4c.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/xpp3/xpp3/1.1.4c/8dd0ddee19fe6ed0182b18e0e621d1c8b4d8d56/xpp3-1.1.4c-sources.jar!/" />
</SOURCES>
</library>
</component>

View File

@ -116,6 +116,31 @@
</content>
<orderEntry type="jdk" jdkName="Android API 26 Platform" jdkType="Android SDK" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="Gradle: org.igniterealtime.smack:smack-resolver-minidns:4.2.0@jar" level="project" />
<orderEntry type="library" name="Gradle: org.jxmpp:jxmpp-jid:0.5.0@jar" level="project" />
<orderEntry type="library" name="Gradle: org.osmdroid:osmdroid-android-6.0.2" level="project" />
<orderEntry type="library" scope="TEST" name="Gradle: com.squareup:javawriter:2.1.1@jar" level="project" />
<orderEntry type="library" name="Gradle: com.android.support.constraint:constraint-layout-1.1.2" level="project" />
<orderEntry type="library" name="Gradle: com.android.support:support-media-compat-26.1.0" level="project" />
<orderEntry type="library" name="Gradle: de.measite.minidns:minidns-hla:0.2.4@jar" level="project" />
<orderEntry type="library" name="Gradle: com.android.support:support-annotations:26.1.0@jar" level="project" />
<orderEntry type="library" name="Gradle: com.android.support:support-v4-26.1.0" level="project" />
<orderEntry type="library" name="Gradle: org.igniterealtime.smack:smack-extensions:4.2.0@jar" level="project" />
<orderEntry type="library" name="Gradle: com.android.support:recyclerview-v7-26.1.0" level="project" />
<orderEntry type="library" scope="TEST" name="Gradle: javax.inject:javax.inject:1@jar" level="project" />
<orderEntry type="library" name="Gradle: xpp3:xpp3:1.1.4c@jar" level="project" />
<orderEntry type="library" name="Gradle: android.arch.lifecycle:common:1.0.0@jar" level="project" />
<orderEntry type="library" name="Gradle: com.android.support:support-vector-drawable-26.1.0" level="project" />
<orderEntry type="library" name="Gradle: com.android.support:support-core-ui-26.1.0" level="project" />
<orderEntry type="library" scope="TEST" name="Gradle: com.android.support.test:monitor-1.0.2" level="project" />
<orderEntry type="library" name="Gradle: com.android.support:support-core-utils-26.1.0" level="project" />
<orderEntry type="library" name="Gradle: com.android.support.constraint:constraint-layout-solver:1.1.2@jar" level="project" />
<orderEntry type="library" name="Gradle: me.dm7.barcodescanner:core-1.9" level="project" />
<orderEntry type="library" name="Gradle: org.igniterealtime.smack:smack-sasl-provided:4.2.0@jar" level="project" />
<orderEntry type="library" name="Gradle: com.android.support:design-26.1.0" level="project" />
<orderEntry type="library" scope="TEST" name="Gradle: net.sf.kxml:kxml2:2.3.0@jar" level="project" />
<orderEntry type="library" name="Gradle: de.measite.minidns:minidns-iterative-resolver:0.2.4@jar" level="project" />
<orderEntry type="library" name="Gradle: org.igniterealtime.smack:smack-tcp:4.2.0@jar" level="project" />
<orderEntry type="library" scope="TEST" name="Gradle: com.android.support.test:runner-1.0.2" level="project" />
<orderEntry type="library" name="Gradle: com.android.support:animated-vector-drawable-26.1.0" level="project" />
<orderEntry type="library" scope="TEST" name="Gradle: com.android.support:support-annotations:27.1.1@jar" level="project" />
@ -123,30 +148,24 @@
<orderEntry type="library" name="Gradle: com.android.support:appcompat-v7-26.1.0" level="project" />
<orderEntry type="library" name="Gradle: com.android.support:support-fragment-26.1.0" level="project" />
<orderEntry type="library" name="Gradle: android.arch.core:common:1.0.0@jar" level="project" />
<orderEntry type="library" name="Gradle: org.osmdroid:osmdroid-android-6.0.2" level="project" />
<orderEntry type="library" scope="TEST" name="Gradle: com.squareup:javawriter:2.1.1@jar" level="project" />
<orderEntry type="library" name="Gradle: com.android.support.constraint:constraint-layout-1.1.2" level="project" />
<orderEntry type="library" name="Gradle: com.android.support:support-media-compat-26.1.0" level="project" />
<orderEntry type="library" name="Gradle: com.android.support:support-annotations:26.1.0@jar" level="project" />
<orderEntry type="library" name="Gradle: com.android.support:support-v4-26.1.0" level="project" />
<orderEntry type="library" name="Gradle: com.android.support:support-compat-26.1.0" level="project" />
<orderEntry type="library" scope="TEST" name="Gradle: com.google.code.findbugs:jsr305:2.0.1@jar" level="project" />
<orderEntry type="library" name="Gradle: com.android.support:recyclerview-v7-26.1.0" level="project" />
<orderEntry type="library" name="Gradle: org.jxmpp:jxmpp-util-cache:0.5.0@jar" level="project" />
<orderEntry type="library" scope="TEST" name="Gradle: com.android.support.test.espresso:espresso-core-3.0.2" level="project" />
<orderEntry type="library" scope="TEST" name="Gradle: javax.inject:javax.inject:1@jar" level="project" />
<orderEntry type="library" name="Gradle: org.igniterealtime.smack:smack-core:4.2.0@jar" level="project" />
<orderEntry type="library" name="Gradle: com.google.zxing:core:3.2.1@jar" level="project" />
<orderEntry type="library" scope="TEST" name="Gradle: junit:junit:4.12@jar" level="project" />
<orderEntry type="library" name="Gradle: android.arch.lifecycle:common:1.0.0@jar" level="project" />
<orderEntry type="library" scope="TEST" name="Gradle: org.hamcrest:hamcrest-core:1.3@jar" level="project" />
<orderEntry type="library" name="Gradle: com.android.support:support-vector-drawable-26.1.0" level="project" />
<orderEntry type="library" name="Gradle: com.android.support:support-core-ui-26.1.0" level="project" />
<orderEntry type="library" scope="TEST" name="Gradle: com.android.support.test:monitor-1.0.2" level="project" />
<orderEntry type="library" name="Gradle: com.android.support:support-core-utils-26.1.0" level="project" />
<orderEntry type="library" scope="TEST" name="Gradle: com.android.support.test.espresso:espresso-idling-resource-3.0.2" level="project" />
<orderEntry type="library" name="Gradle: com.android.support.constraint:constraint-layout-solver:1.1.2@jar" level="project" />
<orderEntry type="library" scope="TEST" name="Gradle: org.hamcrest:hamcrest-library:1.3@jar" level="project" />
<orderEntry type="library" name="Gradle: me.dm7.barcodescanner:zxing-1.9" level="project" />
<orderEntry type="library" name="Gradle: org.jxmpp:jxmpp-core:0.5.0@jar" level="project" />
<orderEntry type="library" scope="TEST" name="Gradle: org.hamcrest:hamcrest-integration:1.3@jar" level="project" />
<orderEntry type="library" name="Gradle: com.android.support:design-26.1.0" level="project" />
<orderEntry type="library" scope="TEST" name="Gradle: net.sf.kxml:kxml2:2.3.0@jar" level="project" />
<orderEntry type="library" name="Gradle: org.igniterealtime.smack:smack-im:4.2.0@jar" level="project" />
<orderEntry type="library" scope="TEST" name="Gradle: org.hamcrest:hamcrest-library:1.3@jar" level="project" />
<orderEntry type="library" name="Gradle: org.igniterealtime.smack:smack-android:4.2.0@jar" level="project" />
<orderEntry type="library" name="Gradle: de.measite.minidns:minidns-core:0.2.4@jar" level="project" />
<orderEntry type="library" name="Gradle: de.measite.minidns:minidns-dnssec:0.2.4@jar" level="project" />
<orderEntry type="library" name="Gradle: org.igniterealtime.smack:smack-android-extensions:4.2.0@jar" level="project" />
<orderEntry type="library" name="Gradle: android.arch.lifecycle:runtime-1.0.0" level="project" />
</component>
</module>

View File

@ -28,4 +28,13 @@ dependencies {
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
implementation 'org.osmdroid:osmdroid-android:6.0.2'
// XMPP (Smack)
//implementation "org.igniterealtime.smack:smack-android:4.2.0"
implementation "org.igniterealtime.smack:smack-android-extensions:4.2.0"
implementation "org.igniterealtime.smack:smack-tcp:4.2.0"
// QR Code (Zxing)
implementation 'com.google.zxing:core:3.2.1'
implementation 'me.dm7.barcodescanner:zxing:1.9'
//implementation 'com.journeyapps:zxing-android-embedded:3.4.0'
}

View File

@ -22,6 +22,9 @@
</activity>
<activity android:name=".FilePicker"></activity>
<activity android:name=".QRCodeGeneratorActivity"></activity>
<activity android:name=".QRCodeReaderActivity"></activity>
</application>
@ -30,4 +33,7 @@
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.VIBRATE"/>
<uses-permission android:name="android.permission.CAMERA" />
</manifest>

View File

@ -19,8 +19,6 @@ import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import fr.chteufleur.mytrackingdog.R;
public class FilePicker extends ListActivity {
public final static String EXTRA_FILE_PATH = "file_path";
@ -40,15 +38,17 @@ public class FilePicker extends ListActivity {
LayoutInflater inflator = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
if (inflator != null) {
View emptyView = inflator.inflate(R.layout.empty_view, null);
((ViewGroup) getListView().getParent()).addView(emptyView);
getListView().setEmptyView(emptyView);
}
// Set initial directory
Directory = new File(DEFAULT_INITIAL_DIRECTORY);
// Initialize the ArrayList
Files = new ArrayList<File>();
Files = new ArrayList<>();
// Set the ListAdapter
Adapter = new FilePickerListAdapter(this, Files);
@ -123,7 +123,7 @@ public class FilePicker extends ListActivity {
private class FilePickerListAdapter extends ArrayAdapter<File> {
private List<File> mObjects;
public FilePickerListAdapter(Context context, List<File> objects) {
private FilePickerListAdapter(Context context, List<File> objects) {
super(context, R.layout.list_item, android.R.id.text1, objects);
mObjects = objects;
}
@ -133,15 +133,17 @@ public class FilePicker extends ListActivity {
View row = null;
if (convertView == null) {
LayoutInflater inflater = (LayoutInflater)
getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
if (inflater != null) {
row = inflater.inflate(R.layout.list_item, parent, false);
}
} else {
row = convertView;
}
File object = mObjects.get(position);
if (row != null) {
ImageView imageView = row.findViewById(R.id.file_picker_image);
TextView textView = row.findViewById(R.id.file_picker_text);
textView.setSingleLine(true);
@ -152,6 +154,7 @@ public class FilePicker extends ListActivity {
} else {
imageView.setImageResource(R.drawable.ic_folder);
}
}
return row;
}
@ -184,7 +187,7 @@ public class FilePicker extends ListActivity {
private String[] Extensions;
public ExtensionFilenameFilter(String[] extensions) {
private ExtensionFilenameFilter(String[] extensions) {
super();
Extensions = extensions;
}
@ -197,8 +200,8 @@ public class FilePicker extends ListActivity {
}
if (Extensions != null && Extensions.length > 0) {
for (int i = 0; i < Extensions.length; i++) {
if (filename.endsWith(Extensions[i])) {
for (String ext: Extensions) {
if (filename.endsWith(ext)) {
// The filename ends with the extension
return true;
}

View File

@ -1,22 +1,26 @@
package fr.chteufleur.mytrackingdog;
import android.Manifest;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.graphics.Color;
import android.hardware.GeomagneticField;
import android.location.Location;
import android.location.LocationManager;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.os.Vibrator;
import android.preference.PreferenceManager;
import android.support.annotation.NonNull;
import android.support.annotation.RequiresApi;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
@ -27,6 +31,9 @@ import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import org.jivesoftware.smack.SmackException;
import org.jivesoftware.smack.XMPPException;
import org.jxmpp.stringprep.XmppStringprepException;
import org.osmdroid.api.IMapController;
import org.osmdroid.config.Configuration;
import org.osmdroid.tileprovider.tilesource.TileSourceFactory;
@ -43,25 +50,33 @@ import org.osmdroid.views.overlay.mylocation.GpsMyLocationProvider;
import org.osmdroid.views.overlay.mylocation.MyLocationNewOverlay;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Observable;
import java.util.Observer;
import fr.chteufleur.mytrackingdog.models.Notification;
import fr.chteufleur.mytrackingdog.models.beans.MyLocation;
import fr.chteufleur.mytrackingdog.models.beans.MyLocationArray;
import fr.chteufleur.mytrackingdog.models.beans.WayPointLocation;
import fr.chteufleur.mytrackingdog.services.ServiceGps;
import fr.chteufleur.mytrackingdog.services.ServiceTrackingDog;
import fr.chteufleur.mytrackingdog.services.ServiceXmpp;
public class MainActivity extends AppCompatActivity implements IOrientationConsumer, Observer {
public static final String TAG = MainActivity.class.getName();
private static final int ACTIVITY_REQUEST_PICK_FILE = 1;
private static final int ACTIVITY_QR_CODE_GENERATOR = 2;
private static final int ACTIVITY_QR_CODE_READER = 3;
private ServiceTrackingDog serviceTrackingDog = null;
public static String appName = "";
private MyLocationNewOverlay mLocationOverlay;
private IOrientationProvider compass = null;
private ServiceGps serviceGps = null;
private Context ctx = null;
private MapView map = null;
@ -76,7 +91,6 @@ public class MainActivity extends AppCompatActivity implements IOrientationConsu
private Button start_stop_trace;
private Button start_stop_dog_trace;
private Button add_object;
private Button center_button;
private TextView textViewCurrentLocation;
private MyLocation lastLocation = null;
@ -91,6 +105,7 @@ public class MainActivity extends AppCompatActivity implements IOrientationConsu
}
}
//<editor-fold defaultstate="collapsed" desc="Activity life cycle">
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@ -118,6 +133,7 @@ public class MainActivity extends AppCompatActivity implements IOrientationConsu
map.setBuiltInZoomControls(false);
map.setMultiTouchControls(true);
map.setOnTouchListener(new View.OnTouchListener() {
@SuppressLint("ClickableViewAccessibility")
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
map.onTouchEvent(motionEvent);
@ -128,7 +144,7 @@ public class MainActivity extends AppCompatActivity implements IOrientationConsu
}
});
center_button = findViewById(R.id.center_button);
Button center_button = findViewById(R.id.center_button);
center_button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
@ -155,6 +171,15 @@ public class MainActivity extends AppCompatActivity implements IOrientationConsu
@Override
public void onClick(View view) {
changeStatusTrace();
try {
if (serviceTrackingDog.isTraceurActivated()) {
serviceTrackingDog.sendXmppCommandStartTrail();
} else {
serviceTrackingDog.sendXmppCommandStopTrail();
}
} catch (XmppStringprepException | XMPPException.XMPPErrorException | SmackException.NotConnectedException | InterruptedException | SmackException.NoResponseException e) {
e.printStackTrace();
}
}
});
start_stop_dog_trace = findViewById(R.id.start_stop_dog_trace);
@ -169,9 +194,13 @@ public class MainActivity extends AppCompatActivity implements IOrientationConsu
add_object.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (serviceGps.isTraceurActivated()) {
addMarker();
} else if (serviceGps.isDogActivated()) {
if (serviceTrackingDog.isTraceurActivated()) {
WayPointLocation loc = serviceTrackingDog.addPointObjectTrail();
if (loc != null) {
GeoPoint gp = new GeoPoint(loc.getLatitude(), loc.getLongitude(), loc.getAltitude());
addMarker(gp, loc.isFound());
}
} else if (serviceTrackingDog.isDogActivated()) {
markAsFound();
}
}
@ -180,102 +209,14 @@ public class MainActivity extends AppCompatActivity implements IOrientationConsu
textViewCurrentLocation = findViewById(R.id.textViewCurrentLocation);
textViewCurrentLocation.setVisibility(View.GONE);
if (serviceGps == null) {
serviceGps = new ServiceGps();
serviceGps.addObserver(this);
}
}
private void changeStatusTrace() {
serviceGps.toggleTraceurActivation();
if (serviceGps.isTraceurActivated()) {
this.start_stop_trace.setText(R.string.trail_stop);
this.add_object.setVisibility(View.VISIBLE);
this.add_object.setText(R.string.trail_object);
this.start_stop_dog_trace.setVisibility(View.GONE);
updateDistance();
} else {
this.start_stop_trace.setText(R.string.trail_start);
this.add_object.setVisibility(View.GONE);
this.start_stop_dog_trace.setVisibility(View.VISIBLE);
}
}
private void changeStatusDogTrace() {
serviceGps.toggleDogActivation();
if (serviceGps.isDogActivated()) {
this.start_stop_dog_trace.setText(R.string.dog_stop);
this.add_object.setVisibility(View.VISIBLE);
this.add_object.setText(R.string.dog_object);
this.start_stop_trace.setVisibility(View.GONE);
this.textViewCurrentLocation.setVisibility(View.GONE);
updateDistance();
} else {
this.start_stop_dog_trace.setText(R.string.dog_start);
this.add_object.setVisibility(View.GONE);
this.start_stop_trace.setVisibility(View.VISIBLE);
}
}
private void addMarker() {
WayPointLocation loc = serviceGps.addPointObjectTrail();
GeoPoint gp = new GeoPoint(loc.getLatitude(), loc.getLongitude(), loc.getAltitude());
addMarker(gp, loc.isFound());
}
private void addMarker(GeoPoint gp, boolean isFound) {
Marker marker = new Marker(map);
marker.setIcon(getResources().getDrawable(isFound ? R.drawable.ic_marker_blue : R.drawable.ic_marker_red));
marker.setPosition(gp);
marker.setAnchor(Marker.ANCHOR_CENTER, Marker.ANCHOR_BOTTOM);
marker.setTitle("Object");
marker.setDraggable(false);
marker.setOnMarkerClickListener(new Marker.OnMarkerClickListener() {
@Override
public boolean onMarkerClick(Marker marker, MapView mapView) {
if (serviceGps.isDogActivated()) {
GeoPoint gp = marker.getPosition();
WayPointLocation wpl = serviceGps.getPointTrail(gp.getLatitude(), gp.getLongitude());
if (wpl != null) {
wpl.setFound();
marker.setIcon(getResources().getDrawable(R.drawable.ic_marker_blue));
marker.setAnchor(Marker.ANCHOR_CENTER, Marker.ANCHOR_BOTTOM);
}
}
return true;
}
});
map.getOverlays().add(marker);
}
private void markAsFound() {
List<WayPointLocation> wpls = serviceGps.foundNearObjects();
boolean findMarker = false;
for (WayPointLocation wpl : wpls) {
if (wpl != null && !wpl.isFound()) {
wpl.setFound();
for (Overlay o : map.getOverlays()) {
if (o instanceof Marker) {
Marker marker = (Marker) o;
GeoPoint gp = marker.getPosition();
if (wpl.isEquals(gp.getLatitude(), gp.getLongitude())) {
marker.setIcon(getResources().getDrawable(R.drawable.ic_marker_blue));
marker.setAnchor(Marker.ANCHOR_CENTER, Marker.ANCHOR_BOTTOM);
break;
}
}
}
serviceGps.addPointObjectDog();
findMarker = true;
break;
}
}
if (wpls.isEmpty() || !findMarker) {
// if no object is near
WayPointLocation wpl = serviceGps.addPointObjectDog();
GeoPoint gp = new GeoPoint(wpl.getLatitude(), wpl.getLongitude(), wpl.getAltitude());
addMarker(gp, true);
if (serviceTrackingDog == null) {
serviceTrackingDog = new ServiceTrackingDog(
(Vibrator) getSystemService(Context.VIBRATOR_SERVICE),
PreferenceManager.getDefaultSharedPreferences(ctx),
getResources()
);
serviceTrackingDog.addObserver(this, ServiceGps.class.getName());
serviceTrackingDog.addObserver(this, ServiceXmpp.class.getName());
}
}
@ -311,9 +252,9 @@ public class MainActivity extends AppCompatActivity implements IOrientationConsu
setRequestedOrientation(orientation);
}
serviceGps.setLocationManager((LocationManager) getSystemService(Context.LOCATION_SERVICE));
serviceGps.setAppName(appName);
serviceGps.start();
serviceTrackingDog.setLocationManager((LocationManager) getSystemService(Context.LOCATION_SERVICE));
serviceTrackingDog.setAppName(appName);
serviceTrackingDog.startLocation();
mLocationOverlay.enableFollowLocation();
mLocationOverlay.enableMyLocation();
@ -351,23 +292,31 @@ public class MainActivity extends AppCompatActivity implements IOrientationConsu
@Override
public void onBackPressed() {
if (serviceGps.isDogActivated() || serviceGps.isTraceurActivated()) {
if (serviceTrackingDog.isDogActivated() || serviceTrackingDog.isTraceurActivated()) {
Toast.makeText(ctx, "Une trace est en cours d'enregistrement.", Toast.LENGTH_LONG).show();
return ;
}
super.onBackPressed();
pause();
if (serviceGps != null) {
serviceGps.stop();
if (serviceTrackingDog != null) {
serviceTrackingDog.close();
}
zoomed = false;
}
//</editor-fold>
//<editor-fold defaultstate="collapsed" desc="Menu management">
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
MenuItem vibrationObjectMenuItem = menu.findItem(R.id.action_active_vibration_object);
vibrationObjectMenuItem.setChecked(serviceTrackingDog.isVibrationNearObjectEnabled());
MenuItem xmppObjectMenuItem = menu.findItem(R.id.action_active_xmpp);
xmppObjectMenuItem.setChecked(serviceTrackingDog.isXmppEnabled());
return true;
}
@ -382,11 +331,19 @@ public class MainActivity extends AppCompatActivity implements IOrientationConsu
if (id == R.id.action_import_gpx) {
Intent intent = new Intent(this, FilePicker.class);
intent.putExtra(FilePicker.EXTRA_FILE_PATH, Environment.getExternalStorageDirectory().getAbsolutePath() + "/" + appName);
startActivityForResult(intent, REQUEST_PICK_FILE);
startActivityForResult(intent, ACTIVITY_REQUEST_PICK_FILE);
return true;
} else if (id == R.id.action_qr_code_generator) {
Intent intent = new Intent(this, QRCodeGeneratorActivity.class);
startActivityForResult(intent, ACTIVITY_QR_CODE_GENERATOR);
} else if (id == R.id.action_qr_code_reader) {
Intent intent = new Intent(this, QRCodeReaderActivity.class);
startActivityForResult(intent, ACTIVITY_QR_CODE_READER);
} else if (id == R.id.action_send_gpx_trail) {
File trailFile = serviceGps.getLastExportedTrailFile();
File trailFile = serviceTrackingDog.getLastExportedTrailFile();
if (trailFile != null) {
Intent shareIntent = new Intent();
shareIntent.setAction(Intent.ACTION_SEND);
@ -398,36 +355,93 @@ public class MainActivity extends AppCompatActivity implements IOrientationConsu
Toast.makeText(ctx, "Aucune trace enregistré.", Toast.LENGTH_LONG).show();
}
return true;
} else if (id == R.id.action_send_gpx_trail_by_xmpp) {
File trailFile = serviceTrackingDog.getLastExportedTrailFile();
if (trailFile != null) {
try {
serviceTrackingDog.sendXmppFile(trailFile);
} catch (XmppStringprepException | SmackException e) {
Toast.makeText(ctx, "Echec de l'envoye de la trace.", Toast.LENGTH_LONG).show();
}
} else {
Toast.makeText(ctx, "Aucune trace enregistré.", Toast.LENGTH_LONG).show();
}
return true;
} else if (id == R.id.action_active_vibration_object) {
boolean checked = item.isChecked();
item.setChecked(!checked);
serviceTrackingDog.setVibrationNearObjectEnabled(!checked);
return true;
} else if (id == R.id.action_active_xmpp) {
boolean checked = item.isChecked();
boolean newStat = !checked;
item.setChecked(newStat);
if (newStat) {
try {
serviceTrackingDog.enableXmpp();
Toast.makeText(ctx, "Connexion XMPP réussie", Toast.LENGTH_SHORT).show();
} catch (InterruptedException | IOException | SmackException | XMPPException e) {
e.printStackTrace();
Toast.makeText(ctx, "Echec de connexion XMPP", Toast.LENGTH_LONG).show();
item.setChecked(false);
serviceTrackingDog.disableXmpp();
}
} else {
serviceTrackingDog.disableXmpp();
}
return true;
}
return super.onOptionsItemSelected(item);
}
private static final int REQUEST_PICK_FILE = 1;
//</editor-fold>
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == RESULT_OK) {
switch (requestCode) {
case REQUEST_PICK_FILE:
case ACTIVITY_REQUEST_PICK_FILE:
if (data.hasExtra(FilePicker.EXTRA_FILE_PATH)) {
serviceGps.importGpxTrace(new File(data.getStringExtra(FilePicker.EXTRA_FILE_PATH)));
serviceTrackingDog.importGpxTrace(new File(data.getStringExtra(FilePicker.EXTRA_FILE_PATH)));
updateDogTrace();
updateTrailTrace();
calculTrailDistance();
for (MyLocation loc: serviceGps.getListGeoPointObjectsTrail()) {
// Update distance
distance = serviceTrackingDog.calculTrailDistance();
if (distance != 0) {
updatePlaceholder();
}
for (MyLocation loc: serviceTrackingDog.getListGeoPointObjectsTrail()) {
addMarker(new GeoPoint(loc.getLatitude(), loc.getLongitude(), loc.getAltitude()), false);
}
for (MyLocation loc: serviceGps.getListGeoPointObjectsDog()) {
for (MyLocation loc: serviceTrackingDog.getListGeoPointObjectsDog()) {
boolean isFound = false;
if (loc instanceof WayPointLocation) {
isFound = ((WayPointLocation) loc).isFound();
}
addMarker(new GeoPoint(loc.getLatitude(), loc.getLongitude(), loc.getAltitude()), isFound);
}
if (!serviceGps.getListGeoPointTraceur().isEmpty()) {
updateDistance(getTextTraceur());
} else if (!serviceGps.getListGeoPointDog().isEmpty()) {
updateDistance(getTextDog());
if (!serviceTrackingDog.getListGeoPointTraceur().isEmpty()) {
updatePlaceholder(getTextTraceur());
} else if (!serviceTrackingDog.getListGeoPointDog().isEmpty()) {
updatePlaceholder(getTextDog());
}
}
break;
case ACTIVITY_QR_CODE_READER:
if (data.hasExtra(QRCodeReaderActivity.EXTRA_SCANNED_TEXT)) {
String text = data.getStringExtra(QRCodeReaderActivity.EXTRA_SCANNED_TEXT);
try {
serviceTrackingDog.setOtherJid(text);
Log.i(TAG, "TEXT: "+text);
} catch (SmackException.NotConnectedException | InterruptedException | XmppStringprepException e) {
Log.e(TAG, "Fail send presence", e);
Toast.makeText(ctx, "Echec connexion avec le matériel", Toast.LENGTH_LONG).show();
}
}
break;
@ -449,11 +463,10 @@ public class MainActivity extends AppCompatActivity implements IOrientationConsu
}
}
@Override
public void onOrientationChanged(float orientationToMagneticNorth, IOrientationProvider source) {
//note, on devices without a compass this never fires...
MyLocation location = serviceGps.getCurrentLocation();
MyLocation location = serviceTrackingDog.getCurrentLocation();
if (location == null) {
return ;
}
@ -468,7 +481,6 @@ public class MainActivity extends AppCompatActivity implements IOrientationConsu
if (gpsspeed < 0.01) {
GeomagneticField gf = new GeomagneticField(lat, lon, alt, timeOfFix);
float trueNorth = orientationToMagneticNorth + gf.getDeclination();
gf = null;
if (trueNorth > 360.0f) {
trueNorth = trueNorth - 360.0f;
}
@ -490,23 +502,96 @@ public class MainActivity extends AppCompatActivity implements IOrientationConsu
}
}
private void calculTrailDistance() {
List<MyLocation> listLoc = serviceGps.getListGeoPointTraceur();
MyLocation last = null;
distance = 0;
for (MyLocation loc: listLoc) {
if (last != null) {
distance += loc.distanceTo(last);
//<editor-fold defaultstate="collapsed" desc="Map management">
private void changeStatusTrace() {
serviceTrackingDog.toggleTraceurActivation();
if (serviceTrackingDog.isTraceurActivated()) {
this.start_stop_trace.setText(R.string.trail_stop);
this.add_object.setVisibility(View.VISIBLE);
this.add_object.setText(R.string.trail_object);
this.start_stop_dog_trace.setVisibility(View.GONE);
updatePlaceholder();
} else {
this.start_stop_trace.setText(R.string.trail_start);
this.add_object.setVisibility(View.GONE);
this.start_stop_dog_trace.setVisibility(View.VISIBLE);
}
last = loc;
}
if (distance != 0) {
updateDistance();
private void changeStatusDogTrace() {
serviceTrackingDog.toggleDogActivation();
if (serviceTrackingDog.isDogActivated()) {
this.start_stop_dog_trace.setText(R.string.dog_stop);
this.add_object.setVisibility(View.VISIBLE);
this.add_object.setText(R.string.dog_object);
this.start_stop_trace.setVisibility(View.GONE);
this.textViewCurrentLocation.setVisibility(View.GONE);
updatePlaceholder();
} else {
this.start_stop_dog_trace.setText(R.string.dog_start);
this.add_object.setVisibility(View.GONE);
this.start_stop_trace.setVisibility(View.VISIBLE);
}
}
private void addMarker(GeoPoint gp, boolean isFound) {
Marker marker = new Marker(map);
marker.setIcon(getResources().getDrawable(isFound ? R.drawable.ic_marker_blue : R.drawable.ic_marker_red));
marker.setPosition(gp);
marker.setAnchor(Marker.ANCHOR_CENTER, Marker.ANCHOR_BOTTOM);
marker.setTitle("Object");
marker.setDraggable(false);
marker.setOnMarkerClickListener(new Marker.OnMarkerClickListener() {
@Override
public boolean onMarkerClick(Marker marker, MapView mapView) {
if (serviceTrackingDog.isDogActivated()) {
GeoPoint gp = marker.getPosition();
WayPointLocation wpl = serviceTrackingDog.getPointTrail(gp.getLatitude(), gp.getLongitude());
if (wpl != null) {
wpl.setFound();
marker.setIcon(getResources().getDrawable(R.drawable.ic_marker_blue));
marker.setAnchor(Marker.ANCHOR_CENTER, Marker.ANCHOR_BOTTOM);
}
}
return true;
}
});
map.getOverlays().add(marker);
}
private void markAsFound() {
List<WayPointLocation> wpls = serviceTrackingDog.foundNearObjects();
boolean findMarker = false;
for (WayPointLocation wpl : wpls) {
if (wpl != null && !wpl.isFound()) {
wpl.setFound();
for (Overlay o : map.getOverlays()) {
if (o instanceof Marker) {
Marker marker = (Marker) o;
GeoPoint gp = marker.getPosition();
if (wpl.isEquals(gp.getLatitude(), gp.getLongitude())) {
marker.setIcon(getResources().getDrawable(R.drawable.ic_marker_blue));
marker.setAnchor(Marker.ANCHOR_CENTER, Marker.ANCHOR_BOTTOM);
break;
}
}
}
serviceTrackingDog.addPointObjectDog();
findMarker = true;
break;
}
}
if (wpls.isEmpty() || !findMarker) {
// if no object is near -> add new found object
WayPointLocation wpl = serviceTrackingDog.addPointObjectDog();
GeoPoint gp = new GeoPoint(wpl.getLatitude(), wpl.getLongitude(), wpl.getAltitude());
addMarker(gp, true);
}
}
private void updateDogTrace() {
MyLocationArray listLoc = serviceGps.getListGeoPointDog();
MyLocationArray listLoc = serviceTrackingDog.getListGeoPointDog();
if (listLoc.isEmpty()) {
return ;
}
@ -524,7 +609,7 @@ public class MainActivity extends AppCompatActivity implements IOrientationConsu
}
private void updateTrailTrace() {
MyLocationArray listLoc = serviceGps.getListGeoPointTraceur();
MyLocationArray listLoc = serviceTrackingDog.getListGeoPointTraceur();
if (listLoc.isEmpty()) {
return ;
}
@ -541,47 +626,6 @@ public class MainActivity extends AppCompatActivity implements IOrientationConsu
map.invalidate();
}
@Override
public void update(Observable observable, Object o) {
if (observable == serviceGps) {
if (o instanceof String && o.equals(ServiceGps.NOTIF_NEW_LOCATION)) {
MyLocation loc = serviceGps.getCurrentLocation();
if (loc != null) {
GeoPoint currentPoint = new GeoPoint(loc.getLatitude(), loc.getLongitude(), loc.getAltitude());
if (mLocationOverlay.isFollowLocationEnabled()) {
map.getController().setCenter(currentPoint);
}
if (serviceGps.isTraceurActivated()) {
updateTrailTrace();
if (lastLocation != null) {
distance += loc.distanceTo(lastLocation);
updateDistance();
}
lastLocation = loc;
} else if (serviceGps.isDogActivated()) {
updateDogTrace();
if (lastLocation != null) {
distance += loc.distanceTo(lastLocation);
updateDistance();
}
lastLocation = loc;
}
float orientation = serviceGps.getOrientation(deviceOrientation);
if (orientation >= 0) {
map.setMapOrientation(orientation);
}
if (!zoomed) {
IMapController mapController = map.getController();
mapController.setZoom(20.0);
zoomed = true;
}
}
}
}
}
private List<GeoPoint> convertListLocation(MyLocationArray list) {
List<GeoPoint> ret = new ArrayList<>();
if (list != null) {
@ -591,25 +635,134 @@ public class MainActivity extends AppCompatActivity implements IOrientationConsu
}
return ret;
}
//</editor-fold>
private void updateDistance() {
//<editor-fold defaultstate="collapsed" desc="Service callback">
@Override
public void update(Observable observable, Object o) {
if (observable.getClass().getName().equals(ServiceGps.class.getName())) {
updateServiceGps((Notification) o);
} else if (observable.getClass().getName().equals(ServiceXmpp.class.getName())) {
updateServiceXmpp((Notification) o);
}
}
public void updateServiceGps(Notification notification) {
if (notification.isAction(ServiceGps.NOTIF_NEW_LOCATION)) {
Location loc = (Location) notification.getExtra(ServiceGps.NOTIF_NEW_LOCATION_VALUE_LOCATION);
if (loc != null) {
onNewLocation(new MyLocation(loc));
}
}
}
public void updateServiceXmpp(Notification notification) {
if (notification.isAction(ServiceXmpp.NOTIF_NEW_LOCATION)) {
if (serviceTrackingDog.isTraceurActivated()) {
MyLocation loc = (MyLocation) notification.getExtra(ServiceXmpp.NOTIF_NEW_LOCATION_VALUE_LOCATION);
onNewLocation(loc);
}
} else if (notification.isAction(ServiceXmpp.NOTIF_NEW_OBJECT)) {
if (serviceTrackingDog.isTraceurActivated()) {
MyLocation locObj = (MyLocation) notification.getExtra(ServiceXmpp.NOTIF_NEW_OBJECT_VALUE_LOCATION);
GeoPoint gp = new GeoPoint(locObj.getLatitude(), locObj.getLongitude(), locObj.getAltitude());
addMarker(gp, false);
}
} else if (notification.isAction(ServiceXmpp.NOTIF_START_TRAIL)) {
runOnUiThread(new Runnable() {
@Override
public void run() {
changeStatusTrace();
}
});
} else if (notification.isAction(ServiceXmpp.NOTIF_STOP_TRAIL)) {
runOnUiThread(new Runnable() {
@Override
public void run() {
changeStatusTrace();
}
});
} else if (notification.isAction(ServiceXmpp.NOTIF_RECEIVING_FILE)) {
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(ctx, "Réception d'un fichier en cours", Toast.LENGTH_SHORT).show();
}
});
} else if (notification.isAction(ServiceXmpp.NOTIF_RECEIVING_FILE_COMPLETTED)) {
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(ctx, "Le fichier a était réceptionné", Toast.LENGTH_SHORT).show();
}
});
} else if (notification.isAction(ServiceXmpp.NOTIF_RECEIVING_FILE_FAIL)) {
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(ctx, "Echec dans la reception du fichier", Toast.LENGTH_LONG).show();
}
});
}
}
private MyLocation onNewLocation = null;
private void onNewLocation(MyLocation loc) {
if (loc != null) {
onNewLocation = loc;
runOnUiThread(new Runnable() {
@Override
public void run() {
GeoPoint currentPoint = new GeoPoint(onNewLocation.getLatitude(), onNewLocation.getLongitude(), onNewLocation.getAltitude());
if (mLocationOverlay.isFollowLocationEnabled()) {
map.getController().setCenter(currentPoint);
}
if (serviceTrackingDog.isTraceurActivated()) {
updateTrailTrace();
distance = serviceTrackingDog.calculTrailDistance();
updatePlaceholder();
lastLocation = onNewLocation;
} else if (serviceTrackingDog.isDogActivated()) {
updateDogTrace();
updatePlaceholder();
lastLocation = onNewLocation;
}
float orientation = serviceTrackingDog.getOrientation(deviceOrientation);
if (orientation >= 0) {
map.setMapOrientation(orientation);
}
if (!zoomed) {
IMapController mapController = map.getController();
mapController.setZoom(19.0);
zoomed = true;
}
}
});
}
}
//</editor-fold>
//<editor-fold defaultstate="collapsed" desc="Placeholder management">
private void updatePlaceholder() {
String text = null;
if (serviceGps.isTraceurActivated()) {
if (serviceTrackingDog.isTraceurActivated()) {
text = getTextTraceur();
} else if (serviceGps.isDogActivated()) {
} else if (serviceTrackingDog.isDogActivated()) {
text = getTextDog();
}
updateDistance(text);
updatePlaceholder(text);
}
private String getTextTraceur() {
return String.format("Distance: %,dm\t\t\t\t\t\t\t\tObjets: %d", ((int) distance), serviceGps.getListGeoPointObjectsTrail().size());
return String.format("Distance: %,dm\t\t\t\t\t\t\t\tObjets: %d", ((int) distance), serviceTrackingDog.getListGeoPointObjectsTrail().size());
}
private String getTextDog() {
String text = "";
MyLocation firstLoc = serviceGps.getListGeoPointDog().getFirstLocation();
MyLocation lastLoc = serviceGps.getListGeoPointDog().getLastLocation();
MyLocation firstLoc = serviceTrackingDog.getListGeoPointDog().getFirstLocation();
MyLocation lastLoc = serviceTrackingDog.getListGeoPointDog().getLastLocation();
if (firstLoc != null) {
long time = lastLoc.getTime() - firstLoc.getTime();
time /= 1_000;
@ -621,20 +774,21 @@ public class MainActivity extends AppCompatActivity implements IOrientationConsu
text = String.format("Time: %02d:%02d:%02d", h, m, s);
int nbFoundObject = 0;
for (MyLocation loc: serviceGps.getListGeoPointObjectsDog()) {
for (MyLocation loc: serviceTrackingDog.getListGeoPointObjectsDog()) {
if (loc instanceof WayPointLocation && ((WayPointLocation) loc).isFound()) {
nbFoundObject++;
}
}
text += "\t\t\t\t\t\t\t\tObjets: "+nbFoundObject+"/"+serviceGps.getListGeoPointObjectsTrail().size();
text += "\t\t\t\t\t\t\t\tObjets: "+nbFoundObject+"/"+serviceTrackingDog.getListGeoPointObjectsTrail().size();
}
return text;
}
private void updateDistance(String text) {
private void updatePlaceholder(String text) {
if (text != null) {
this.textViewCurrentLocation.setText(text);
this.textViewCurrentLocation.setVisibility(View.VISIBLE);
}
}
//</editor-fold>
}

View File

@ -0,0 +1,90 @@
package fr.chteufleur.mytrackingdog;
import android.app.Activity;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import android.view.View;
import android.view.WindowManager;
import android.widget.ImageView;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.WriterException;
import com.google.zxing.common.BitMatrix;
public class QRCodeGeneratorActivity extends Activity {
public static final String TAG = QRCodeGeneratorActivity.class.getName();
public final static int QRcodeWidth = 500 ;
private ImageView imageView;
private static Bitmap image = null;
private static boolean generating = false;
public static QRCodeGeneratorActivity thsi = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.qr_code_generator);
thsi = this;
// Keep screen ON
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
imageView = findViewById(R.id.qr_code_image);
while (generating) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
}
}
if (image != null) {
imageView.setImageBitmap(image);
}
imageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
onBackPressed();
}
});
}
public static void textToImageEncode(String value, Resources resources) throws WriterException {
generating = true;
Log.i(TAG, "QR CODE "+value);
BitMatrix bitMatrix;
try {
bitMatrix = new MultiFormatWriter().encode(
value,
BarcodeFormat.DATA_MATRIX.QR_CODE,
QRcodeWidth, QRcodeWidth, null
);
} catch (IllegalArgumentException Illegalargumentexception) {
return;
}
int bitMatrixWidth = bitMatrix.getWidth();
int bitMatrixHeight = bitMatrix.getHeight();
int[] pixels = new int[bitMatrixWidth * bitMatrixHeight];
for (int y = 0; y < bitMatrixHeight; y++) {
int offset = y * bitMatrixWidth;
for (int x = 0; x < bitMatrixWidth; x++) {
pixels[offset + x] = bitMatrix.get(x, y) ?
resources.getColor(R.color.black):resources.getColor(R.color.white);
}
}
image = Bitmap.createBitmap(bitMatrixWidth, bitMatrixHeight, Bitmap.Config.ARGB_4444);
image.setPixels(pixels, 0, 500, 0, 0, bitMatrixWidth, bitMatrixHeight);
Log.i(TAG, "FIN GENERATION QR CODE");
generating = false;
}
public static void pressBackButton() {
if (thsi != null) {
thsi.finish();
}
}
}

View File

@ -0,0 +1,69 @@
package fr.chteufleur.mytrackingdog;
import android.Manifest;
import android.app.Activity;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.RequiresApi;
import android.view.WindowManager;
import com.google.zxing.Result;
import me.dm7.barcodescanner.zxing.ZXingScannerView;
public class QRCodeReaderActivity extends Activity implements ZXingScannerView.ResultHandler {
private final int REQUEST_CODE_ASK_PERMISSION = 123;
public static final String EXTRA_SCANNED_TEXT = "scanned_text";
public static final String TAG = QRCodeReaderActivity.class.getName();
private ZXingScannerView mScannerView;
@RequiresApi(api = Build.VERSION_CODES.M)
protected void checkPermissions() {
int hasCameraPermission = checkSelfPermission(Manifest.permission.CAMERA);
if (hasCameraPermission != PackageManager.PERMISSION_GRANTED) {
requestPermissions(new String[]{Manifest.permission.CAMERA}, REQUEST_CODE_ASK_PERMISSION);
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
checkPermissions();
}
setContentView(R.layout.qr_code_reader);
// Keep screen ON
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
mScannerView = new ZXingScannerView(this);
setContentView(mScannerView);
}
@Override
public void onResume() {
super.onResume();
mScannerView.setResultHandler(this); // Register ourselves as a handler for scan results.
mScannerView.startCamera(); // Start camera on resume
}
@Override
public void onPause() {
super.onPause();
mScannerView.stopCamera(); // Stop camera on pause
}
@Override
public void handleResult(Result rawResult) {
Intent extra = new Intent();
extra.putExtra(EXTRA_SCANNED_TEXT, rawResult.getText());
setResult(RESULT_OK, extra);
finish();
}
}

View File

@ -28,7 +28,6 @@ public class ImportGpx extends Gpx {
private String traceName = "";
public ImportGpx(File filePath) {
super(filePath);
}
@ -37,10 +36,9 @@ public class ImportGpx extends Gpx {
return this.traceName;
}
public List parse() throws XmlPullParserException, IOException {
public List<MyLocation> parse() throws XmlPullParserException, IOException {
InputStream in = new FileInputStream(filePath);
try {
XmlPullParser parser = Xml.newPullParser();
parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false);
parser.setInput(in, null);
@ -52,8 +50,8 @@ public class ImportGpx extends Gpx {
}
private List readGpx(XmlPullParser parser) throws XmlPullParserException, IOException {
List entries = new ArrayList();
private List<MyLocation> readGpx(XmlPullParser parser) throws XmlPullParserException, IOException {
List<MyLocation> entries = new ArrayList<>();
parser.require(XmlPullParser.START_TAG, null, "gpx");
while (parser.next() != XmlPullParser.END_TAG) {
@ -72,8 +70,8 @@ public class ImportGpx extends Gpx {
return entries;
}
private List readTrk(XmlPullParser parser) throws XmlPullParserException, IOException {
List entries = new ArrayList();
private List<MyLocation> readTrk(XmlPullParser parser) throws XmlPullParserException, IOException {
List<MyLocation> entries = new ArrayList<>();
parser.require(XmlPullParser.START_TAG, null, "trk");
while (parser.next() != XmlPullParser.END_TAG) {
@ -90,8 +88,8 @@ public class ImportGpx extends Gpx {
return entries;
}
private List readTrkseq(XmlPullParser parser) throws XmlPullParserException, IOException {
List entries = new ArrayList();
private List<MyLocation> readTrkseq(XmlPullParser parser) throws XmlPullParserException, IOException {
List<MyLocation> entries = new ArrayList<>();
parser.require(XmlPullParser.START_TAG, null, "trkseg");
while (parser.next() != XmlPullParser.END_TAG) {
@ -205,7 +203,7 @@ public class ImportGpx extends Gpx {
private boolean readFound(XmlPullParser parser) throws XmlPullParserException, IOException {
boolean ret = false;
boolean ret;
parser.require(XmlPullParser.START_TAG, null, "found");
ret = Boolean.parseBoolean(readText(parser));
parser.require(XmlPullParser.END_TAG, null, "found");

View File

@ -0,0 +1,42 @@
package fr.chteufleur.mytrackingdog.models;
import java.util.HashMap;
import java.util.Map;
public class Notification {
private final String action;
private final Map<String, Object> extras;
public Notification(String action) {
this(action, new HashMap<String, Object>());
}
public Notification(String action, Map<String, Object> extras) {
this.action = action;
this.extras = extras;
}
public boolean isAction(String action) {
boolean ret = false;
if (action != null) {
ret = this.action.equals(action);
}
return ret;
}
public Notification addExtra(String param, Object value) {
if (extras != null) {
extras.put(param, value);
}
return this;
}
public Object getExtra(String param) {
Object ret = null;
if (extras != null && extras.containsKey(param)) {
ret = extras.get(param);
}
return ret;
}
}

View File

@ -10,27 +10,35 @@ public class Traces {
private static final String TAG = Traces.class.getName();
private MyLocationArray listPointTraceur = new MyLocationArray();
private MyLocationArray listPointDog = new MyLocationArray();
private MyLocationArray listPointObjectsTrail = new MyLocationArray();
private MyLocationArray listPointObjectsDog = new MyLocationArray();
private final MyLocationArray listPointTraceur = new MyLocationArray();
private final MyLocationArray listPointDog = new MyLocationArray();
private final MyLocationArray listPointObjectsTrail = new MyLocationArray();
private final MyLocationArray listPointObjectsDog = new MyLocationArray();
private boolean traceurActivated = false;
private boolean dogActivated = false;
public void addPointTraceur(MyLocation point) {
if (point != null) {
listPointTraceur.add(point);
}
}
public void addPointDog(MyLocation point) {
if (point != null) {
listPointDog.add(point);
}
}
public void addPointObjectTrail(WayPointLocation point) {
if (point != null) {
listPointObjectsTrail.add(point);
}
}
public void addPointObjectDog(WayPointLocation point) {
if (point != null) {
listPointObjectsDog.add(point);
}
}
public WayPointLocation getPointObjectTrail(double lat, double lon) {
WayPointLocation ret = null;
for (MyLocation ml: listPointObjectsTrail) {

View File

@ -0,0 +1,119 @@
package fr.chteufleur.mytrackingdog.models.xmpp.commands;
import org.jivesoftware.smack.SmackException;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smackx.commands.AdHocCommandNote;
import org.jivesoftware.smackx.commands.LocalCommand;
import org.jivesoftware.smackx.xdata.Form;
import org.jivesoftware.smackx.xdata.FormField;
import org.jivesoftware.smackx.xdata.packet.DataForm;
import org.jxmpp.jid.Jid;
import java.util.List;
import fr.chteufleur.mytrackingdog.services.ServiceXmpp;
public class ObjectGeolocCommand extends LocalCommand {
public static final String TAG = ObjectGeolocCommand.class.getName();
public static final String FIELD_PARAM_LATITUDE = "latitude";
public static final String FIELD_PARAM_LONGITUDE = "longitude";
public static final String FIELD_PARAM_TIME = "time";
private final ServiceXmpp serviceXmpp;
public ObjectGeolocCommand(ServiceXmpp serviceXmpp) {
this.serviceXmpp = serviceXmpp;
}
@Override
public boolean isLastStage() {
return getCurrentStage() == 1;
}
@Override
public boolean hasPermission(Jid jid) {
return true;
}
@Override
public void execute() throws SmackException.NoResponseException, XMPPException.XMPPErrorException, SmackException.NotConnectedException, InterruptedException {
Form result = new Form(DataForm.Type.form);
setExecuteAction(Action.next);
FormField resultFieldLatitude = new FormField(FIELD_PARAM_LATITUDE);
resultFieldLatitude.setLabel(FIELD_PARAM_LATITUDE);
resultFieldLatitude.setType(FormField.Type.text_single);
result.addField(resultFieldLatitude);
FormField resultFieldLongitude = new FormField(FIELD_PARAM_LONGITUDE);
resultFieldLongitude.setLabel(FIELD_PARAM_LONGITUDE);
resultFieldLongitude.setType(FormField.Type.text_single);
result.addField(resultFieldLongitude);
FormField resultFieldTime = new FormField(FIELD_PARAM_TIME);
resultFieldTime.setLabel(FIELD_PARAM_TIME);
resultFieldTime.setType(FormField.Type.text_single);
result.addField(resultFieldTime);
this.addActionAvailable(Action.next);
setForm(result);
}
@Override
public void next(Form response) throws SmackException.NoResponseException, XMPPException.XMPPErrorException, SmackException.NotConnectedException, InterruptedException {
FormField formLatitude = response.getField(FIELD_PARAM_LATITUDE);
FormField formLongitude = response.getField(FIELD_PARAM_LONGITUDE);
FormField formTime = response.getField(FIELD_PARAM_TIME);
if (formLatitude != null && formLongitude != null && formTime != null) {
List<String> latitudeStrs = formLatitude.getValues();
List<String> longitudeStrs = response.getField(FIELD_PARAM_LONGITUDE).getValues();
List<String> timeStrs = response.getField(FIELD_PARAM_TIME).getValues();
double latitude = 0, longitude = 0;
long time = 0;
for (String latitudeStr : latitudeStrs) {
try {
latitude = Double.parseDouble(latitudeStr);
break;
} catch (NumberFormatException ex) {
}
}
for (String longitudeStr : longitudeStrs) {
try {
longitude = Double.parseDouble(longitudeStr);
break;
} catch (NumberFormatException ex) {
}
}
for (String timeStr : timeStrs) {
try {
time = Long.parseLong(timeStr);
break;
} catch (NumberFormatException ex) {
}
}
if (serviceXmpp != null && latitude != 0 && longitude != 0 && time != 0) {
serviceXmpp.addObjectGeoloc(latitude, longitude, time);
}
this.addNote(new AdHocCommandNote(AdHocCommandNote.Type.info, "SUCCESS"));
} else {
this.addNote((new AdHocCommandNote(AdHocCommandNote.Type.error, "FAIL")));
}
}
@Override
public void complete(Form response) throws SmackException.NoResponseException, XMPPException.XMPPErrorException, SmackException.NotConnectedException, InterruptedException {
}
@Override
public void prev() throws SmackException.NoResponseException, XMPPException.XMPPErrorException, SmackException.NotConnectedException, InterruptedException {
}
@Override
public void cancel() throws SmackException.NoResponseException, XMPPException.XMPPErrorException, SmackException.NotConnectedException, InterruptedException {
}
}

View File

@ -0,0 +1,53 @@
package fr.chteufleur.mytrackingdog.models.xmpp.commands;
import org.jivesoftware.smack.SmackException;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smackx.commands.AdHocCommandNote;
import org.jivesoftware.smackx.commands.LocalCommand;
import org.jivesoftware.smackx.xdata.Form;
import org.jxmpp.jid.Jid;
import fr.chteufleur.mytrackingdog.services.ServiceXmpp;
public class StartTrailGeolocCommand extends LocalCommand {
private final ServiceXmpp serviceXmpp;
public StartTrailGeolocCommand(ServiceXmpp serviceXmpp) {
this.serviceXmpp = serviceXmpp;
}
@Override
public boolean isLastStage() {
return true;
}
@Override
public boolean hasPermission(Jid jid) {
return true;
}
@Override
public void execute() throws SmackException.NoResponseException, XMPPException.XMPPErrorException, SmackException.NotConnectedException, InterruptedException {
if (serviceXmpp != null) {
serviceXmpp.startTrailGeoloc();
}
this.addNote(new AdHocCommandNote(AdHocCommandNote.Type.info, "SUCCESS"));
}
@Override
public void next(Form response) throws SmackException.NoResponseException, XMPPException.XMPPErrorException, SmackException.NotConnectedException, InterruptedException {
}
@Override
public void complete(Form response) throws SmackException.NoResponseException, XMPPException.XMPPErrorException, SmackException.NotConnectedException, InterruptedException {
}
@Override
public void prev() throws SmackException.NoResponseException, XMPPException.XMPPErrorException, SmackException.NotConnectedException, InterruptedException {
}
@Override
public void cancel() throws SmackException.NoResponseException, XMPPException.XMPPErrorException, SmackException.NotConnectedException, InterruptedException {
}
}

View File

@ -0,0 +1,53 @@
package fr.chteufleur.mytrackingdog.models.xmpp.commands;
import org.jivesoftware.smack.SmackException;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smackx.commands.AdHocCommandNote;
import org.jivesoftware.smackx.commands.LocalCommand;
import org.jivesoftware.smackx.xdata.Form;
import org.jxmpp.jid.Jid;
import fr.chteufleur.mytrackingdog.services.ServiceXmpp;
public class StopTrailGeolocCommand extends LocalCommand {
private final ServiceXmpp serviceXmpp;
public StopTrailGeolocCommand(ServiceXmpp serviceXmpp) {
this.serviceXmpp = serviceXmpp;
}
@Override
public boolean isLastStage() {
return true;
}
@Override
public boolean hasPermission(Jid jid) {
return true;
}
@Override
public void execute() throws SmackException.NoResponseException, XMPPException.XMPPErrorException, SmackException.NotConnectedException, InterruptedException {
if (serviceXmpp != null) {
serviceXmpp.stopTrailGeoloc();
}
this.addNote(new AdHocCommandNote(AdHocCommandNote.Type.info, "SUCCESS"));
}
@Override
public void next(Form response) throws SmackException.NoResponseException, XMPPException.XMPPErrorException, SmackException.NotConnectedException, InterruptedException {
}
@Override
public void complete(Form response) throws SmackException.NoResponseException, XMPPException.XMPPErrorException, SmackException.NotConnectedException, InterruptedException {
}
@Override
public void prev() throws SmackException.NoResponseException, XMPPException.XMPPErrorException, SmackException.NotConnectedException, InterruptedException {
}
@Override
public void cancel() throws SmackException.NoResponseException, XMPPException.XMPPErrorException, SmackException.NotConnectedException, InterruptedException {
}
}

View File

@ -0,0 +1,119 @@
package fr.chteufleur.mytrackingdog.models.xmpp.commands;
import org.jivesoftware.smack.SmackException;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smackx.commands.AdHocCommandNote;
import org.jivesoftware.smackx.commands.LocalCommand;
import org.jivesoftware.smackx.xdata.Form;
import org.jivesoftware.smackx.xdata.FormField;
import org.jivesoftware.smackx.xdata.packet.DataForm;
import org.jxmpp.jid.Jid;
import java.util.List;
import fr.chteufleur.mytrackingdog.services.ServiceXmpp;
public class TrailGeolocCommand extends LocalCommand {
public static final String TAG = TrailGeolocCommand.class.getName();
public static final String FIELD_PARAM_LATITUDE = "latitude";
public static final String FIELD_PARAM_LONGITUDE = "longitude";
public static final String FIELD_PARAM_TIME = "time";
private final ServiceXmpp serviceXmpp;
public TrailGeolocCommand(ServiceXmpp serviceXmpp) {
this.serviceXmpp = serviceXmpp;
}
@Override
public boolean isLastStage() {
return getCurrentStage() == 1;
}
@Override
public boolean hasPermission(Jid jid) {
return true;
}
@Override
public void execute() throws SmackException.NoResponseException, XMPPException.XMPPErrorException, SmackException.NotConnectedException, InterruptedException {
Form result = new Form(DataForm.Type.form);
setExecuteAction(Action.next);
FormField resultFieldLatitude = new FormField(FIELD_PARAM_LATITUDE);
resultFieldLatitude.setLabel(FIELD_PARAM_LATITUDE);
resultFieldLatitude.setType(FormField.Type.text_single);
result.addField(resultFieldLatitude);
FormField resultFieldLongitude = new FormField(FIELD_PARAM_LONGITUDE);
resultFieldLongitude.setLabel(FIELD_PARAM_LONGITUDE);
resultFieldLongitude.setType(FormField.Type.text_single);
result.addField(resultFieldLongitude);
FormField resultFieldTime = new FormField(FIELD_PARAM_TIME);
resultFieldTime.setLabel(FIELD_PARAM_TIME);
resultFieldTime.setType(FormField.Type.text_single);
result.addField(resultFieldTime);
this.addActionAvailable(Action.next);
setForm(result);
}
@Override
public void next(Form response) throws SmackException.NoResponseException, XMPPException.XMPPErrorException, SmackException.NotConnectedException, InterruptedException {
FormField formLatitude = response.getField(FIELD_PARAM_LATITUDE);
FormField formLongitude = response.getField(FIELD_PARAM_LONGITUDE);
FormField formTime = response.getField(FIELD_PARAM_TIME);
if (formLatitude != null && formLongitude != null && formTime != null) {
List<String> latitudeStrs = formLatitude.getValues();
List<String> longitudeStrs = response.getField(FIELD_PARAM_LONGITUDE).getValues();
List<String> timeStrs = response.getField(FIELD_PARAM_TIME).getValues();
double latitude = 0, longitude = 0;
long time = 0;
for (String latitudeStr : latitudeStrs) {
try {
latitude = Double.parseDouble(latitudeStr);
break;
} catch (NumberFormatException ex) {
}
}
for (String longitudeStr : longitudeStrs) {
try {
longitude = Double.parseDouble(longitudeStr);
break;
} catch (NumberFormatException ex) {
}
}
for (String timeStr : timeStrs) {
try {
time = Long.parseLong(timeStr);
break;
} catch (NumberFormatException ex) {
}
}
if (serviceXmpp != null && latitude != 0 && longitude != 0 && time != 0) {
serviceXmpp.addTrailGeoloc(latitude, longitude, time);
}
this.addNote(new AdHocCommandNote(AdHocCommandNote.Type.info, "SUCCESS"));
} else {
this.addNote((new AdHocCommandNote(AdHocCommandNote.Type.error, "FAIL")));
}
}
@Override
public void complete(Form response) throws SmackException.NoResponseException, XMPPException.XMPPErrorException, SmackException.NotConnectedException, InterruptedException {
}
@Override
public void prev() throws SmackException.NoResponseException, XMPPException.XMPPErrorException, SmackException.NotConnectedException, InterruptedException {
}
@Override
public void cancel() throws SmackException.NoResponseException, XMPPException.XMPPErrorException, SmackException.NotConnectedException, InterruptedException {
}
}

View File

@ -1,8 +0,0 @@
package fr.chteufleur.mytrackingdog.services;
public interface IServiceGps {
public void start();
public void stop();
}

View File

@ -5,72 +5,26 @@ import android.location.LocationListener;
import android.location.LocationManager;
import android.location.LocationProvider;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import org.xmlpull.v1.XmlPullParserException;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Observable;
import fr.chteufleur.mytrackingdog.models.ExportGpx;
import fr.chteufleur.mytrackingdog.models.Gpx;
import fr.chteufleur.mytrackingdog.models.ImportGpx;
import fr.chteufleur.mytrackingdog.models.Traces;
import fr.chteufleur.mytrackingdog.models.beans.MyLocation;
import fr.chteufleur.mytrackingdog.models.beans.MyLocationArray;
import fr.chteufleur.mytrackingdog.models.beans.TraceLocation;
import fr.chteufleur.mytrackingdog.models.beans.WayPointLocation;
import fr.chteufleur.mytrackingdog.models.Notification;
public class ServiceGps extends Observable implements IServiceGps, LocationListener {
public class ServiceGps extends Observable implements LocationListener {
private static final String TAG = ServiceGps.class.getName();
public static final String NOTIF_NEW_LOCATION = "fr.chteufleur.mytrackingdog.services.servicegps.newlocation";
private File lastExportedTrailFile = null;
public static final String NOTIF_NEW_LOCATION = ServiceGps.class.getName()+".newlocation";
public static final String NOTIF_NEW_LOCATION_VALUE_LOCATION = NOTIF_NEW_LOCATION+".value.location";
private LocationManager locationManager;
private MyLocation currentLocation = null;
private String appName = "";
private final Traces traces = new Traces();
public void setLocationManager(LocationManager locationManager) {
this.locationManager = locationManager;
}
public void setAppName(String appName) {
this.appName = appName;
}
public MyLocation getCurrentLocation() {
return currentLocation;
}
public float getOrientation(int deviceOrientation) {
float ret = -1;
if (currentLocation != null && currentLocation.getSpeed() >= 0.01) {
ret = (360 - currentLocation.getBearing() - deviceOrientation);
if (ret < 0) {
ret += 360;
}
if (ret > 360) {
ret -= 360;
}
//help smooth everything out
ret = (int) ret;
ret = ret / 5;
ret = (int) ret;
ret = ret * 5;
}
return ret;
}
@Override
public void start() {
try {
// if (locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
@ -84,20 +38,17 @@ public class ServiceGps extends Observable implements IServiceGps, LocationListe
}
}
@Override
public void stop() {
this.locationManager.removeUpdates(this);
Log.i(TAG, "Stop location");
}
//<editor-fold defaultstate="collapsed" desc="GPS Callback">
@Override
public void onLocationChanged(Location location) {
Log.i(TAG, "onLocationChanged");
currentLocation = new MyLocation(location);
traces.addCurrentPoint(currentLocation);
setChanged();
notifyObservers(NOTIF_NEW_LOCATION);
notifyObservers(new Notification(NOTIF_NEW_LOCATION).addExtra(NOTIF_NEW_LOCATION_VALUE_LOCATION, location));
}
@Override
@ -106,9 +57,9 @@ public class ServiceGps extends Observable implements IServiceGps, LocationListe
if (s != null && s.equals(LocationManager.GPS_PROVIDER)) {
if (i == LocationProvider.AVAILABLE) {
start();
} else if (i == LocationProvider.TEMPORARILY_UNAVAILABLE) {
} else if (i == LocationProvider.OUT_OF_SERVICE) {
stop();
// } else if (i == LocationProvider.TEMPORARILY_UNAVAILABLE) {
}
}
}
@ -128,133 +79,5 @@ public class ServiceGps extends Observable implements IServiceGps, LocationListe
stop();
}
}
public void toggleTraceurActivation() {
traces.toggleTraceurActivation();
if (!isTraceurActivated()) {
exportTrailTraceToGpx();
}
}
public boolean isTraceurActivated() {
return traces.isTraceurActivated();
}
public void toggleDogActivation() {
traces.toggleDogActivation();
if (!isDogActivated()) {
exportDogTraceToGpx();
}
}
public boolean isDogActivated() {
return traces.isDogActivated();
}
public WayPointLocation addPointObjectTrail() {
WayPointLocation wpl = null;
if (currentLocation != null) {
wpl = new WayPointLocation(currentLocation);
traces.addPointObjectTrail(wpl);
}
return wpl;
}
public WayPointLocation addPointObjectDog() {
WayPointLocation wpl = null;
if (currentLocation != null) {
wpl = new WayPointLocation(currentLocation);
wpl.setFound();
traces.addPointObjectDog(wpl);
}
return wpl;
}
public MyLocationArray getListGeoPointTraceur() {
return traces.getListPointTraceur();
}
public MyLocationArray getListGeoPointDog() {
return traces.getListPointDog();
}
public MyLocationArray getListGeoPointObjectsTrail() {
return traces.getListPointObjectsTrail();
}
public MyLocationArray getListGeoPointObjectsDog() {
return traces.getListPointObjectsDog();
}
public WayPointLocation getPointTrail(double lat, double lon) {
return traces.getPointObjectTrail(lat, lon);
}
public WayPointLocation getPointDog(double lat, double lon) {
return traces.getPointObjectDog(lat, lon);
}
public List<WayPointLocation> foundNearObjects() {
List<WayPointLocation> ret = new ArrayList<>();
MyLocation curLoc = currentLocation;
for (MyLocation ml: getListGeoPointObjectsTrail()) {
if (curLoc.distanceTo(ml) < 10 && ml instanceof WayPointLocation) {
ret.add((WayPointLocation) ml);
}
}
return ret;
}
public String getFileName(String prefix) {
SimpleDateFormat formater = new SimpleDateFormat("yyyy_MM_dd_HH_mm_ss");
String date = formater.format(new Date());
return Environment.getExternalStorageDirectory().getAbsolutePath() + "/"
+ appName + "/" + date + "_" + prefix
+ ".gpx";
}
public boolean exportDogTraceToGpx() {
File file = new File(getFileName(Gpx.DOG_TRACE_NAME));
ExportGpx exportGpx = new ExportGpx(file, Gpx.DOG_TRACE_NAME);
exportGpx.setObjects(traces.getListPointObjectsDog());
exportGpx.setTrace(traces.getListPointDog());
return exportGpx.export();
}
public boolean exportTrailTraceToGpx() {
File file = new File(getFileName(Gpx.TRAIL_TRACE_NAME));
ExportGpx exportGpx = new ExportGpx(file, Gpx.TRAIL_TRACE_NAME);
exportGpx.setObjects(traces.getListPointObjectsTrail());
exportGpx.setTrace(traces.getListPointTraceur());
lastExportedTrailFile = file;
return exportGpx.export();
}
public File getLastExportedTrailFile() {
return lastExportedTrailFile;
}
public void importGpxTrace(File file) {
ImportGpx importGpx = new ImportGpx(file);
try {
List list = importGpx.parse();
String traceName = importGpx.getTraceName();
if (traceName.equals(Gpx.TRAIL_TRACE_NAME)) {
lastExportedTrailFile = file;
}
for (int i=0; i<list.size(); i++) {
Object o = list.get(i);
if (o instanceof WayPointLocation) {
if (traceName.equals(Gpx.DOG_TRACE_NAME)) {
traces.addPointObjectDog((WayPointLocation) o);
} else if (traceName.equals(Gpx.TRAIL_TRACE_NAME)) {
traces.addPointObjectTrail((WayPointLocation) o);
}
} else if (o instanceof TraceLocation) {
if (traceName.equals(Gpx.DOG_TRACE_NAME)) {
traces.addPointDog((TraceLocation) o);
} else if (traceName.equals(Gpx.TRAIL_TRACE_NAME)) {
traces.addPointTraceur((TraceLocation) o);
}
}
}
} catch (XmlPullParserException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
//</editor-fold>
}

View File

@ -0,0 +1,455 @@
package fr.chteufleur.mytrackingdog.services;
import android.content.SharedPreferences;
import android.content.res.Resources;
import android.location.Location;
import android.location.LocationManager;
import android.os.Build;
import android.os.Environment;
import android.os.VibrationEffect;
import android.os.Vibrator;
import org.jivesoftware.smack.SmackException;
import org.jivesoftware.smack.XMPPException;
import org.jxmpp.stringprep.XmppStringprepException;
import org.xmlpull.v1.XmlPullParserException;
import java.io.File;
import java.io.IOException;
import java.net.UnknownHostException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Observable;
import java.util.Observer;
import fr.chteufleur.mytrackingdog.QRCodeGeneratorActivity;
import fr.chteufleur.mytrackingdog.models.ExportGpx;
import fr.chteufleur.mytrackingdog.models.Gpx;
import fr.chteufleur.mytrackingdog.models.ImportGpx;
import fr.chteufleur.mytrackingdog.models.Notification;
import fr.chteufleur.mytrackingdog.models.Traces;
import fr.chteufleur.mytrackingdog.models.beans.MyLocation;
import fr.chteufleur.mytrackingdog.models.beans.MyLocationArray;
import fr.chteufleur.mytrackingdog.models.beans.TraceLocation;
import fr.chteufleur.mytrackingdog.models.beans.WayPointLocation;
public class ServiceTrackingDog implements Observer {
private enum LocationProvider {
GPS,
XMPP
}
//<editor-fold defaultstate="collapsed" desc="Preferences">
private final SharedPreferences preferences;
private static final String PREF_VIBRATION_NEAR_OBJECT_ENABLED = "PREF_VIBRATION_NEAR_OBJECT_ENABLED";
//</editor-fold>
private final ServiceGps serviceGps;
private final ServiceXmpp serviceXmpp;
private final Traces traces = new Traces();
private String appName = "";
private LocationProvider currentLocationProvider = LocationProvider.GPS;
private MyLocation currentLocation = null;
public ServiceTrackingDog(Vibrator vibrator, SharedPreferences preferences, Resources resources) {
this.vibrator = vibrator;
this.preferences = preferences;
if (preferences != null) {
this.vibrationNearObjectEnabled = preferences.getBoolean(PREF_VIBRATION_NEAR_OBJECT_ENABLED, false);
}
this.serviceGps = new ServiceGps();
this.serviceGps.addObserver(this);
ServiceXmpp sx;
try {
sx = new ServiceXmpp(resources);
sx.addObserver(this);
} catch (UnknownHostException | XmppStringprepException ex) {
sx = null;
}
this.serviceXmpp = sx;
}
public void setAppName(String appName) {
this.appName = appName;
if (serviceXmpp != null) {
serviceXmpp.setAppName(appName);
}
}
public void addObserver(Observer observer, String name) {
if (name != null) {
if (name.equals(ServiceGps.class.getName())) {
serviceGps.addObserver(observer);
} else if (name.equals(ServiceXmpp.class.getName())) {
serviceXmpp.addObserver(observer);
}
}
}
public void close() {
serviceGps.stop();
if (serviceXmpp != null) {
serviceXmpp.close();
}
}
//<editor-fold defaultstate="collapsed" desc="Location management">
public MyLocation getCurrentLocation() {
return currentLocation;
}
public float getOrientation(int deviceOrientation) {
float ret = -1;
if (currentLocation != null && currentLocation.getSpeed() >= 0.01) {
ret = (360 - currentLocation.getBearing() - deviceOrientation);
if (ret < 0) {
ret += 360;
}
if (ret > 360) {
ret -= 360;
}
//help smooth everything out
ret = (int) ret;
ret = ret / 5;
ret = (int) ret;
ret = ret * 5;
}
return ret;
}
public LocationProvider getCurrentLocationProvider() {
return currentLocationProvider;
}
//</editor-fold>
//<editor-fold defaultstate="collapsed" desc="Trace management">
//<editor-fold defaultstate="collapsed" desc="Trace activation">
public void toggleTraceurActivation() {
traces.toggleTraceurActivation();
if (!isTraceurActivated()) {
exportTrailTraceToGpx();
}
}
public boolean isTraceurActivated() {
return traces.isTraceurActivated();
}
public void toggleDogActivation() {
traces.toggleDogActivation();
if (!isDogActivated()) {
exportDogTraceToGpx();
} else {
currentLocationProvider = LocationProvider.GPS;
}
}
public boolean isDogActivated() {
return traces.isDogActivated();
}
//</editor-fold>
//<editor-fold defaultstate="collapsed" desc="Objects">
public WayPointLocation addPointObjectTrail() {
try {
sendXmppCommandObjectTrail(currentLocation.getLatitude(), currentLocation.getLongitude(), currentLocation.getTime());
} catch (Exception e) {
e.printStackTrace();
}
return addPointObjectTrail(currentLocation);
}
private WayPointLocation addPointObjectTrail(MyLocation location) {
WayPointLocation wpl = null;
if (location != null) {
wpl = new WayPointLocation(location);
traces.addPointObjectTrail(wpl);
}
return wpl;
}
public WayPointLocation addPointObjectDog() {
WayPointLocation wpl = null;
if (currentLocation != null) {
wpl = new WayPointLocation(currentLocation);
wpl.setFound();
traces.addPointObjectDog(wpl);
}
return wpl;
}
public MyLocationArray getListGeoPointObjectsTrail() {
return traces.getListPointObjectsTrail();
}
public MyLocationArray getListGeoPointObjectsDog() {
return traces.getListPointObjectsDog();
}
private List<WayPointLocation> foundNearObjects(int distance) {
List<WayPointLocation> ret = new ArrayList<>();
MyLocation curLoc = currentLocation;
for (MyLocation ml: getListGeoPointObjectsTrail()) {
if (curLoc.distanceTo(ml) < distance && ml instanceof WayPointLocation) {
ret.add((WayPointLocation) ml);
}
}
return ret;
}
public boolean isNearObjects() {
return !foundNearObjects(20).isEmpty();
}
public List<WayPointLocation> foundNearObjects() {
return foundNearObjects(10);
}
//</editor-fold>
//<editor-fold defaultstate="collapsed" desc="Traces">
public void addPoint(MyLocation location) {
traces.addCurrentPoint(location);
}
public MyLocationArray getListGeoPointTraceur() {
return traces.getListPointTraceur();
}
public MyLocationArray getListGeoPointDog() {
return traces.getListPointDog();
}
public WayPointLocation getPointTrail(double lat, double lon) {
return traces.getPointObjectTrail(lat, lon);
}
public WayPointLocation getPointDog(double lat, double lon) {
return traces.getPointObjectDog(lat, lon);
}
public float calculTrailDistance() {
List<MyLocation> listLoc = getListGeoPointTraceur();
MyLocation last = null;
float distance = 0;
for (MyLocation loc: getListGeoPointTraceur()) {
if (last != null) {
distance += loc.distanceTo(last);
}
last = loc;
}
return distance;
}
//</editor-fold>
//</editor-fold>
//<editor-fold defaultstate="collapsed" desc="Observer Callback">
@Override
public void update(Observable observable, Object o) {
if (observable == serviceGps) {
updateGps((Notification) o);
} else if (observable == serviceXmpp) {
updateXmpp((Notification) o);
}
}
public void updateGps(Notification notification) {
if (notification.isAction(ServiceGps.NOTIF_NEW_LOCATION)) {
if (currentLocationProvider == LocationProvider.GPS) {
MyLocation location = new MyLocation((Location) notification.getExtra(ServiceGps.NOTIF_NEW_LOCATION_VALUE_LOCATION));
onNewLocation(location);
shouldVibrate();
if (serviceXmpp != null && location != null && isTraceurActivated()) {
try {
sendXmppCommandLocationTrail(location.getLatitude(), location.getLongitude(), location.getTime());
} catch (Exception ex) {
}
}
}
}
}
public void updateXmpp(Notification notification) {
if (notification.isAction(ServiceXmpp.NOTIF_NEW_LOCATION)) {
if (currentLocationProvider == LocationProvider.XMPP) {
MyLocation location = (MyLocation) notification.getExtra(ServiceXmpp.NOTIF_NEW_LOCATION_VALUE_LOCATION);
onNewLocation(location);
}
} else if (notification.isAction(ServiceXmpp.NOTIF_NEW_OBJECT)) {
MyLocation location = (MyLocation) notification.getExtra(ServiceXmpp.NOTIF_NEW_OBJECT_VALUE_LOCATION);
addPointObjectTrail(location);
} else if (notification.isAction(ServiceXmpp.NOTIF_START_TRAIL)) {
currentLocationProvider = LocationProvider.XMPP;
} else if (notification.isAction(ServiceXmpp.NOTIF_STOP_TRAIL)) {
currentLocationProvider = LocationProvider.GPS;
} else if (notification.isAction(ServiceXmpp.NOTIF_NEW_PRESENCE_RECEIVED)) {
QRCodeGeneratorActivity.pressBackButton();
}
}
public void onNewLocation(MyLocation location) {
if (location != null) {
currentLocation = location;
addPoint(currentLocation);
}
}
//</editor-fold>
//<editor-fold defaultstate="collapsed" desc="Vibration management">
private static final int TIME_VIBRATION_NEAR_OBJECT_MS = 1_000;
private final Vibrator vibrator;
private boolean vibrationNearObjectEnabled = false;
private boolean nearObjectVibration = false;
public void setVibrationNearObjectEnabled(boolean b) {
this.vibrationNearObjectEnabled = b;
if (preferences != null) {
SharedPreferences.Editor editor = preferences.edit();
editor.putBoolean(PREF_VIBRATION_NEAR_OBJECT_ENABLED, b);
editor.commit();
}
}
public boolean isVibrationNearObjectEnabled() {
return this.vibrationNearObjectEnabled;
}
private void vibrate(int timeVibrationMs) {
if (this.vibrator != null) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
this.vibrator.vibrate(VibrationEffect.createOneShot(timeVibrationMs, VibrationEffect.DEFAULT_AMPLITUDE));
} else {
this.vibrator.vibrate(timeVibrationMs);
}
}
}
private void shouldVibrate() {
// Near object vibration check
if (isDogActivated()) {
if (vibrationNearObjectEnabled && isNearObjects()) {
if (!nearObjectVibration) {
nearObjectVibration = true;
vibrate(TIME_VIBRATION_NEAR_OBJECT_MS);
}
} else {
nearObjectVibration = false;
}
}
}
//</editor-fold>
//<editor-fold defaultstate="collapsed" desc="Service GPS delegation">
public void setLocationManager(LocationManager locationManager) {
serviceGps.setLocationManager(locationManager);
}
public void startLocation() {
serviceGps.start();
}
//</editor-fold>
//<editor-fold defaultstate="collapsed" desc="Service XMPP delegation">
public void enableXmpp() throws InterruptedException, XMPPException, SmackException, IOException {
if (serviceXmpp != null) {
serviceXmpp.enable();
}
}
public void disableXmpp() {
if (serviceXmpp != null) {
serviceXmpp.disable();
}
}
public boolean isXmppEnabled() {
boolean ret = false;
if (serviceXmpp != null) {
ret = serviceXmpp.isEnabled();
}
return ret;
}
public void setOtherJid(String otherJid) throws SmackException.NotConnectedException, InterruptedException, XmppStringprepException {
if (serviceXmpp != null && otherJid != null) {
serviceXmpp.setOtherJid(otherJid);
serviceXmpp.sendPresenceAvailable();
}
}
public void sendXmppFile(File file) throws XmppStringprepException, SmackException {
if (serviceXmpp != null) {
serviceXmpp.sendFile(file);
}
}
//<editor-fold defaultstate="collapsed" desc="Commands">
public void sendXmppCommandStartTrail() throws XmppStringprepException, XMPPException.XMPPErrorException, SmackException.NotConnectedException, InterruptedException, SmackException.NoResponseException {
if (serviceXmpp != null) {
serviceXmpp.sendCommandStartTrail();
}
}
public void sendXmppCommandStopTrail() throws XmppStringprepException, XMPPException.XMPPErrorException, SmackException.NotConnectedException, InterruptedException, SmackException.NoResponseException {
if (serviceXmpp != null) {
serviceXmpp.sendCommandStopTrail();
}
}
private void sendXmppCommandObjectTrail(double lat, double lon, long time) throws Exception {
if (serviceXmpp != null) {
serviceXmpp.sendCommandObjectTrail(lat, lon, time);
}
}
private void sendXmppCommandLocationTrail(double lat, double lon, long time) throws Exception {
if (serviceXmpp != null) {
serviceXmpp.sendCommandLocationTrail(lat, lon, time);
}
}
//</editor-fold>
//</editor-fold>
//<editor-fold defaultstate="collapsed" desc="Import/Export">
private File lastExportedTrailFile = null;
private String getFileName(String prefix) {
SimpleDateFormat formater = new SimpleDateFormat("yyyy_MM_dd_HH_mm_ss");
String date = formater.format(new Date());
return Environment.getExternalStorageDirectory().getAbsolutePath() + "/"
+ appName + "/" + date + "_" + prefix
+ ".gpx";
}
public File getLastExportedTrailFile() {
return lastExportedTrailFile;
}
private boolean exportDogTraceToGpx() {
File file = new File(getFileName(Gpx.DOG_TRACE_NAME));
ExportGpx exportGpx = new ExportGpx(file, Gpx.DOG_TRACE_NAME);
exportGpx.setObjects(traces.getListPointObjectsDog());
exportGpx.setTrace(traces.getListPointDog());
return exportGpx.export();
}
private boolean exportTrailTraceToGpx() {
File file = new File(getFileName(Gpx.TRAIL_TRACE_NAME));
ExportGpx exportGpx = new ExportGpx(file, Gpx.TRAIL_TRACE_NAME);
exportGpx.setObjects(traces.getListPointObjectsTrail());
exportGpx.setTrace(traces.getListPointTraceur());
lastExportedTrailFile = file;
return exportGpx.export();
}
public void importGpxTrace(File file) {
ImportGpx importGpx = new ImportGpx(file);
try {
List<MyLocation> list = importGpx.parse();
String traceName = importGpx.getTraceName();
if (traceName.equals(Gpx.TRAIL_TRACE_NAME)) {
lastExportedTrailFile = file;
}
for (int i=0; i<list.size(); i++) {
MyLocation o = list.get(i);
if (o instanceof WayPointLocation) {
if (traceName.equals(Gpx.DOG_TRACE_NAME)) {
traces.addPointObjectDog((WayPointLocation) o);
} else if (traceName.equals(Gpx.TRAIL_TRACE_NAME)) {
traces.addPointObjectTrail((WayPointLocation) o);
}
} else if (o instanceof TraceLocation) {
if (traceName.equals(Gpx.DOG_TRACE_NAME)) {
traces.addPointDog((TraceLocation) o);
} else if (traceName.equals(Gpx.TRAIL_TRACE_NAME)) {
traces.addPointTraceur((TraceLocation) o);
}
}
}
} catch (XmlPullParserException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
//</editor-fold>
}

View File

@ -0,0 +1,419 @@
package fr.chteufleur.mytrackingdog.services;
import android.content.res.Resources;
import android.os.Environment;
import android.os.StrictMode;
import android.util.Log;
import com.google.zxing.WriterException;
import org.jivesoftware.smack.AbstractXMPPConnection;
import org.jivesoftware.smack.ConnectionConfiguration;
import org.jivesoftware.smack.SmackException;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.packet.Presence;
import org.jivesoftware.smack.roster.PresenceEventListener;
import org.jivesoftware.smack.roster.Roster;
import org.jivesoftware.smack.tcp.XMPPTCPConnection;
import org.jivesoftware.smack.tcp.XMPPTCPConnectionConfiguration;
import org.jivesoftware.smackx.commands.AdHocCommandManager;
import org.jivesoftware.smackx.commands.LocalCommand;
import org.jivesoftware.smackx.commands.LocalCommandFactory;
import org.jivesoftware.smackx.commands.RemoteCommand;
import org.jivesoftware.smackx.filetransfer.FileTransfer;
import org.jivesoftware.smackx.filetransfer.FileTransferListener;
import org.jivesoftware.smackx.filetransfer.FileTransferManager;
import org.jivesoftware.smackx.filetransfer.FileTransferRequest;
import org.jivesoftware.smackx.filetransfer.IncomingFileTransfer;
import org.jivesoftware.smackx.filetransfer.OutgoingFileTransfer;
import org.jivesoftware.smackx.xdata.Form;
import org.jxmpp.jid.BareJid;
import org.jxmpp.jid.FullJid;
import org.jxmpp.jid.Jid;
import org.jxmpp.jid.impl.JidCreate;
import org.jxmpp.stringprep.XmppStringprepException;
import java.io.File;
import java.io.IOException;
import java.net.Inet4Address;
import java.net.UnknownHostException;
import java.util.Observable;
import fr.chteufleur.mytrackingdog.QRCodeGeneratorActivity;
import fr.chteufleur.mytrackingdog.models.Notification;
import fr.chteufleur.mytrackingdog.models.beans.MyLocation;
import fr.chteufleur.mytrackingdog.models.xmpp.commands.ObjectGeolocCommand;
import fr.chteufleur.mytrackingdog.models.xmpp.commands.StartTrailGeolocCommand;
import fr.chteufleur.mytrackingdog.models.xmpp.commands.StopTrailGeolocCommand;
import fr.chteufleur.mytrackingdog.models.xmpp.commands.TrailGeolocCommand;
public class ServiceXmpp extends Observable implements PresenceEventListener, FileTransferListener {
public static final String TAG = ServiceXmpp.class.getName();
public static final String NOTIF_NEW_LOCATION = ServiceXmpp.class.getName()+".newlocation";
public static final String NOTIF_NEW_OBJECT = ServiceXmpp.class.getName()+".newobject";
public static final String NOTIF_START_TRAIL = ServiceXmpp.class.getName()+".starttrail";
public static final String NOTIF_STOP_TRAIL = ServiceXmpp.class.getName()+".stoptrail";
public static final String NOTIF_NEW_PRESENCE_RECEIVED = ServiceXmpp.class.getName()+".newpresencereceived";
public static final String NOTIF_RECEIVING_FILE = ServiceXmpp.class.getName()+".receivingfile";
public static final String NOTIF_RECEIVING_FILE_COMPLETTED = NOTIF_RECEIVING_FILE+".completed";
public static final String NOTIF_RECEIVING_FILE_FAIL = NOTIF_RECEIVING_FILE+".receivingfile";
public static final String NOTIF_NEW_OBJECT_VALUE_LOCATION = NOTIF_NEW_OBJECT+".value.location";
public static final String NOTIF_NEW_LOCATION_VALUE_LOCATION = NOTIF_NEW_LOCATION+".value.location";
public static final String NOTIF_NEW_PRESENCE_RECEIVED_VALUE_JID = NOTIF_NEW_PRESENCE_RECEIVED+".value.jid";
private static final String XMPP_NODE_TRAIL_GEOLOC = "trail_geoloc";
private static final String XMPP_NODE_OBJECT_GEOLOC = "object_geoloc";
private static final String XMPP_NODE_START_TRAIL_GEOLOC = "start_trail_geoloc";
private static final String XMPP_NODE_STOP_TRAIL_GEOLOC = "stop_trail_geoloc";
private static final String XMPP_IP_SERVER = "51.254.205.203";
private static final String XMPP_DOMAIN_SERVER = "anon.xmpp.kingpenguin.tk";
private static final int XMPP_PORT = 5222;
private String appName = "";
private final Resources resources;
private final XMPPTCPConnectionConfiguration configuration;
private AdHocCommandManager commandManager;
private FileTransferManager fileManager;
private AbstractXMPPConnection connection;
private String jid;
private String otherJid;
private final ServiceXmpp thsi;
private boolean isEnable = false;
public ServiceXmpp(Resources resources) throws UnknownHostException, XmppStringprepException {
this.resources = resources;
this.configuration = XMPPTCPConnectionConfiguration.builder()
.setSecurityMode(ConnectionConfiguration.SecurityMode.ifpossible)
.setHostAddress(Inet4Address.getByName(XMPP_IP_SERVER))
.setPort(XMPP_PORT)
.setXmppDomain(XMPP_DOMAIN_SERVER)
.setDebuggerEnabled(true)
.performSaslAnonymousAuthentication()
.setKeystoreType(null)
.build();
this.thsi = this;
}
public void setAppName(String appName) {
this.appName = appName;
}
public boolean connect() throws InterruptedException, XMPPException, SmackException, IOException {
if (!isEnable) {
return false;
}
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
boolean isConnected;
connection = new XMPPTCPConnection(configuration);
commandManager = AdHocCommandManager.getAddHocCommandsManager(connection);
fileManager = FileTransferManager.getInstanceFor(connection);
connection.connect();
connection.login();
registerCommands();
fileManager.addFileTransferListener(this);
Roster roster = Roster.getInstanceFor(connection);
roster.addPresenceEventListener(this);
isConnected = connection.isConnected();
if (isConnected) {
jid = connection.getUser().asFullJidIfPossible().toString();
Log.i(TAG, "JID: "+jid);
setPresenceAvailable();
}
Runnable r = new Runnable() {
@Override
public void run() {
try {
QRCodeGeneratorActivity.textToImageEncode(jid, resources);
} catch (WriterException ex) {
Log.e(TAG, "Failed to generate QR Code");
}
}
};
new Thread(r).start();
return isConnected;
}
public void close() {
if (otherJid != null) {
try {
sendPresenceUnavailable(otherJid);
} catch (SmackException.NotConnectedException | InterruptedException | XmppStringprepException ex) {
ex.printStackTrace();
}
}
if (connection != null) {
connection.disconnect();
}
}
public void enable() throws InterruptedException, IOException, SmackException, XMPPException {
this.isEnable = true;
connect();
}
public void disable() {
this.isEnable = false;
close();
}
public boolean isEnabled() {
return isEnable;
}
//<editor-fold defaultstate="collapsed" desc="Presence">
public void sendPresenceAvailable() throws SmackException.NotConnectedException, InterruptedException, XmppStringprepException {
if (otherJid != null) {
sendPresence(JidCreate.fullFrom(otherJid), Presence.Type.available);
}
}
public void sendPresenceAvailable(String to) throws SmackException.NotConnectedException, InterruptedException, XmppStringprepException {
sendPresence(JidCreate.fullFrom(to), Presence.Type.available);
}
public void sendPresenceUnavailable(String to) throws SmackException.NotConnectedException, InterruptedException, XmppStringprepException {
sendPresence(JidCreate.fullFrom(to), Presence.Type.unavailable);
}
private void sendPresence(Jid to, Presence.Type type) throws SmackException.NotConnectedException, InterruptedException {
if (connection != null) {
Presence presence = new Presence(to, type);
presence.setStatus("");
connection.sendStanza(presence);
}
}
private void setPresenceAvailable() throws SmackException.NotConnectedException, InterruptedException {
if (connection != null) {
Presence presence = new Presence(Presence.Type.available);
presence.setStatus("");
connection.sendStanza(presence);
}
}
@Override
public void presenceAvailable(FullJid address, Presence presence) {
String fullJid = address.asFullJidIfPossible().toString();
if (presence.getType() == Presence.Type.available) {
if (!fullJid.equals(jid) && (otherJid == null || !fullJid.equals(otherJid))) {
Log.i(TAG, "PRESENCE AVAILABLE RECEIVED FROM " + fullJid);
otherJid = fullJid;
try {
sendPresenceAvailable(fullJid);
} catch (SmackException.NotConnectedException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (XmppStringprepException e) {
e.printStackTrace();
}
setChanged();
notifyObservers(new Notification(NOTIF_NEW_PRESENCE_RECEIVED).addExtra(NOTIF_NEW_PRESENCE_RECEIVED_VALUE_JID, otherJid));
}
} else if (presence.getType() == Presence.Type.unavailable) {
if (otherJid != null && otherJid.equals(fullJid)) {
otherJid = null;
}
}
}
@Override
public void presenceUnavailable(FullJid address, Presence presence) {
}
@Override
public void presenceError(Jid address, Presence errorPresence) {
}
@Override
public void presenceSubscribed(BareJid address, Presence subscribedPresence) {
}
@Override
public void presenceUnsubscribed(BareJid address, Presence unsubscribedPresence) {
}
//</editor-fold>
//<editor-fold defaultstate="collapsed" desc="Commands">
private void registerCommands() {
commandManager.registerCommand(XMPP_NODE_TRAIL_GEOLOC, XMPP_NODE_TRAIL_GEOLOC, new LocalCommandFactory() {
@Override
public LocalCommand getInstance() {
return new TrailGeolocCommand(thsi);
}
});
commandManager.registerCommand(XMPP_NODE_OBJECT_GEOLOC, XMPP_NODE_OBJECT_GEOLOC, new LocalCommandFactory() {
@Override
public LocalCommand getInstance() {
return new ObjectGeolocCommand(thsi);
}
});
commandManager.registerCommand(XMPP_NODE_START_TRAIL_GEOLOC, XMPP_NODE_START_TRAIL_GEOLOC, new LocalCommandFactory() {
@Override
public LocalCommand getInstance() {
return new StartTrailGeolocCommand(thsi);
}
});
commandManager.registerCommand(XMPP_NODE_STOP_TRAIL_GEOLOC, XMPP_NODE_STOP_TRAIL_GEOLOC, new LocalCommandFactory() {
@Override
public LocalCommand getInstance() {
return new StopTrailGeolocCommand(thsi);
}
});
}
public void startTrailGeoloc() {
Log.i(TAG, "Start trail");
setChanged();
notifyObservers(new Notification(NOTIF_START_TRAIL));
}
public void stopTrailGeoloc() {
Log.i(TAG, "Stop trail");
setChanged();
notifyObservers(new Notification(NOTIF_STOP_TRAIL));
}
public void addTrailGeoloc(double lat, double lon, long time) {
Log.i(TAG, "Add location");
MyLocation location = new MyLocation(lat, lon, time);
setChanged();
notifyObservers(new Notification(NOTIF_NEW_LOCATION).addExtra(NOTIF_NEW_LOCATION_VALUE_LOCATION, location));
}
public void addObjectGeoloc(double lat, double lon, long time) {
Log.i(TAG, "Add object");
MyLocation objectLocation = new MyLocation(lat, lon, time);
setChanged();
notifyObservers(new Notification(NOTIF_NEW_OBJECT).addExtra(NOTIF_NEW_OBJECT_VALUE_LOCATION, objectLocation));
}
public void sendCommandStartTrail() throws XmppStringprepException, XMPPException.XMPPErrorException, SmackException.NotConnectedException, InterruptedException, SmackException.NoResponseException {
if (isOtherJidSet()) {
Log.i(TAG, "Send command start");
RemoteCommand command = commandManager.getRemoteCommand(JidCreate.fullFrom(otherJid), XMPP_NODE_START_TRAIL_GEOLOC);
command.execute();
}
}
public void sendCommandStopTrail() throws XmppStringprepException, XMPPException.XMPPErrorException, SmackException.NotConnectedException, InterruptedException, SmackException.NoResponseException {
if (isOtherJidSet()) {
Log.i(TAG, "Send command stop");
RemoteCommand command = commandManager.getRemoteCommand(JidCreate.fullFrom(otherJid), XMPP_NODE_STOP_TRAIL_GEOLOC);
command.execute();
}
}
public void sendCommandObjectTrail(double lat, double lon, long time) throws Exception {
if (isOtherJidSet()) {
Log.i(TAG, "Send command object");
RemoteCommand command = commandManager.getRemoteCommand(JidCreate.fullFrom(otherJid), XMPP_NODE_OBJECT_GEOLOC);
command.execute();
if (command.getForm() == null) {
throw new Exception("Didn't get form back");
}
Form form = command.getForm().createAnswerForm();
form.setAnswer(ObjectGeolocCommand.FIELD_PARAM_LATITUDE, lat);
form.setAnswer(ObjectGeolocCommand.FIELD_PARAM_LONGITUDE, lon);
form.setAnswer(ObjectGeolocCommand.FIELD_PARAM_TIME, time);
command.next(form);
}
}
public void sendCommandLocationTrail(double lat, double lon, long time) throws Exception {
if (isOtherJidSet()) {
Log.i(TAG, "Send command location");
RemoteCommand command = commandManager.getRemoteCommand(JidCreate.fullFrom(otherJid), XMPP_NODE_TRAIL_GEOLOC);
command.execute();
if (command.getForm() == null) {
throw new Exception("Didn't get form back");
}
Form form = command.getForm().createAnswerForm();
form.setAnswer(TrailGeolocCommand.FIELD_PARAM_LATITUDE, lat);
form.setAnswer(TrailGeolocCommand.FIELD_PARAM_LONGITUDE, lon);
form.setAnswer(TrailGeolocCommand.FIELD_PARAM_TIME, time);
command.next(form);
}
}
//</editor-fold>
//<editor-fold defaultstate="collapsed" desc="File transfert">
// Example: https://github.com/igniterealtime/Smack/blob/master/documentation/extensions/filetransfer.md
public void sendFile(File file) throws XmppStringprepException, SmackException {
if (isOtherJidSet()) {
// Create the outgoing file transfer
OutgoingFileTransfer transfer = fileManager.createOutgoingFileTransfer(JidCreate.entityFullFrom(otherJid));
// Send the file
transfer.sendFile(file, file.getName());
}
}
@Override
public void fileTransferRequest(FileTransferRequest request) {
// Check to see if the request should be accepted
String fullJid = request.getRequestor().asFullJidIfPossible().toString();
if (otherJid != null && fullJid.equals(otherJid)) {
// Accept it
IncomingFileTransfer transfer = request.accept();
File destFile = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/" + appName + "/" + request.getFileName());
try {
transfer.recieveFile(destFile);
setChanged();
notifyObservers(new Notification(NOTIF_RECEIVING_FILE));
while(!transfer.isDone()) {
if (transfer.getStatus().equals(FileTransfer.Status.error)) {
Log.i(TAG, "File transfert error");
setChanged();
notifyObservers(new Notification(NOTIF_RECEIVING_FILE_FAIL));
} else {
Log.i(TAG, "File transfert ("+transfer.getStatus()+"): "+(transfer.getProgress() * 100) + " %");
}
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if (transfer.getStatus().equals(FileTransfer.Status.error)) {
Log.e(TAG, "File transfert error");
destFile.delete();
} else {
Log.i(TAG, "File transfert done (" + transfer.getStatus() + ")");
setChanged();
notifyObservers(new Notification(NOTIF_RECEIVING_FILE_COMPLETTED));
}
} catch (SmackException | IOException e) {
e.printStackTrace();
setChanged();
notifyObservers(new Notification(NOTIF_RECEIVING_FILE_FAIL));
}
} else {
// Reject it
try {
request.reject();
} catch (SmackException.NotConnectedException | InterruptedException e) {
e.printStackTrace();
}
}
}
//</editor-fold>
public void setOtherJid(String otherJid) {
this.otherJid = otherJid;
}
public boolean isOtherJidSet() {
return this.otherJid != null;
}
}

View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="fr.chteufleur.mytrackingdog.QRCodeGeneratorActivity">
<ImageView
android:id="@+id/qr_code_image"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="20dp" />
</LinearLayout>

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="fr.chteufleur.mytrackingdog.QRCodeReaderActivity">
</RelativeLayout>

View File

@ -12,4 +12,31 @@
android:orderInCategory="100"
android:title="@string/action_send_gpx_trail"
app:showAsAction="never" />
<item
android:id="@+id/action_send_gpx_trail_by_xmpp"
android:orderInCategory="100"
android:title="@string/action_send_gpx_trail_by_xmpp"
app:showAsAction="never" />
<item
android:id="@+id/action_active_vibration_object"
android:checkable="true"
android:orderInCategory="100"
android:title="@string/action_active_vibration_object"
app:showAsAction="never" />
<item
android:id="@+id/action_qr_code_generator"
android:orderInCategory="100"
android:title="@string/action_qr_code_generator"
app:showAsAction="never" />
<item
android:id="@+id/action_qr_code_reader"
android:orderInCategory="100"
android:title="@string/action_qr_code_reader"
app:showAsAction="never" />
<item
android:id="@+id/action_active_xmpp"
android:checkable="true"
android:orderInCategory="100"
android:title="@string/action_active_xmpp"
app:showAsAction="never" />
</menu>

View File

@ -3,4 +3,6 @@
<color name="colorPrimary">#3F51B5</color>
<color name="colorPrimaryDark">#303F9F</color>
<color name="colorAccent">#FF4081</color>
<color name="black">#000000</color>
<color name="white">#ffffff</color>
</resources>

View File

@ -1,3 +1,5 @@
<resources>
<dimen name="fab_margin">16dp</dimen>
<dimen name="activity_horizontal_margin">16dp</dimen>
<dimen name="activity_vertical_margin">16dp</dimen>
</resources>

View File

@ -9,5 +9,10 @@
<string name="action_import_gpx">Import GPX</string>
<string name="action_send_gpx_trail">Envoyer trace du traceur</string>
<string name="action_send_gpx_trail_by_xmpp">Envoyer trace du traceur par XMPP</string>
<string name="action_send_to">Envoyer par</string>
<string name="action_active_vibration_object">Active vibration objets</string>
<string name="action_qr_code_generator">Affiche identifiant</string>
<string name="action_qr_code_reader">Lecture identifiant</string>
<string name="action_active_xmpp">Active XMPP</string>
</resources>