├── .gitattributes
├── .gitignore
├── .idea
├── .gitignore
├── .name
├── compiler.xml
├── jarRepositories.xml
└── misc.xml
├── LICENSE
├── README.md
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── moveTrackLib
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── ic_launcher-playstore.png
│ ├── java
│ └── org
│ │ └── moveTrack
│ │ ├── AppStatus.java
│ │ ├── AutoDiscoverer.java
│ │ ├── GyroListener.java
│ │ ├── Handshaker.java
│ │ ├── TrackingService.java
│ │ ├── UDPGyroProviderClient.java
│ │ └── math
│ │ ├── MadgwickAHRS.java
│ │ ├── Quaternion.java
│ │ └── Vector3.java
│ └── res
│ ├── drawable
│ ├── empty_tall_divider.xml
│ ├── error_missing.xml
│ ├── ic_baseline_computer_24.xml
│ ├── ic_baseline_help_outline_24.xml
│ ├── ic_baseline_home_24.xml
│ └── not_missing.xml
│ ├── mipmap-anydpi-v26
│ ├── ic_launcher.xml
│ └── ic_launcher_round.xml
│ ├── mipmap-hdpi
│ ├── ic_launcher.png
│ ├── ic_launcher_background.png
│ ├── ic_launcher_foreground.png
│ └── ic_launcher_round.png
│ ├── mipmap-mdpi
│ ├── ic_launcher.png
│ ├── ic_launcher_background.png
│ ├── ic_launcher_foreground.png
│ └── ic_launcher_round.png
│ ├── mipmap-xhdpi
│ ├── ic_launcher.png
│ ├── ic_launcher_background.png
│ ├── ic_launcher_foreground.png
│ └── ic_launcher_round.png
│ ├── mipmap-xxhdpi
│ ├── ic_launcher.png
│ ├── ic_launcher_background.png
│ ├── ic_launcher_foreground.png
│ └── ic_launcher_round.png
│ ├── mipmap-xxxhdpi
│ ├── ic_launcher.png
│ ├── ic_launcher_background.png
│ ├── ic_launcher_foreground.png
│ └── ic_launcher_round.png
│ ├── values-night
│ └── themes.xml
│ └── values
│ └── colors.xml
├── moveTrackMobile
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── org
│ │ └── moveTrack
│ │ └── Mobile
│ │ ├── MainActivity.java
│ │ └── ui
│ │ ├── ConnectFragment.java
│ │ ├── GenericBindingFragment.java
│ │ ├── SensorInfoFragment.java
│ │ ├── debugLogFragment.java
│ │ └── homeMenu.java
│ └── res
│ ├── drawable-v24
│ └── ic_launcher_foreground.xml
│ ├── drawable
│ └── ic_launcher_background.xml
│ ├── layout
│ ├── activity_main.xml
│ ├── fragment_connect.xml
│ ├── fragment_debug_log.xml
│ ├── fragment_home_menu.xml
│ └── fragment_sensor_info.xml
│ ├── menu
│ └── main_menu.xml
│ ├── mipmap-anydpi-v26
│ ├── ic_launcher.xml
│ └── ic_launcher_round.xml
│ ├── mipmap-hdpi
│ ├── ic_launcher.png
│ ├── ic_launcher_background.png
│ ├── ic_launcher_foreground.png
│ └── ic_launcher_round.png
│ ├── mipmap-mdpi
│ ├── ic_launcher.png
│ ├── ic_launcher_background.png
│ ├── ic_launcher_foreground.png
│ └── ic_launcher_round.png
│ ├── mipmap-xhdpi
│ ├── ic_launcher.png
│ ├── ic_launcher_background.png
│ ├── ic_launcher_foreground.png
│ └── ic_launcher_round.png
│ ├── mipmap-xxhdpi
│ ├── ic_launcher.png
│ ├── ic_launcher_background.png
│ ├── ic_launcher_foreground.png
│ └── ic_launcher_round.png
│ ├── mipmap-xxxhdpi
│ ├── ic_launcher.png
│ ├── ic_launcher_background.png
│ ├── ic_launcher_foreground.png
│ └── ic_launcher_round.png
│ ├── navigation
│ └── nav_graph.xml
│ ├── values-night
│ └── themes.xml
│ └── values
│ ├── attrs.xml
│ ├── sensors.xml
│ ├── strings.xml
│ └── themes.xml
├── moveTrackWear
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── org
│ │ └── moveTrack
│ │ └── Wear
│ │ └── MainWear.java
│ └── res
│ ├── layout
│ └── activity_mainwear.xml
│ ├── mipmap-anydpi-v26
│ ├── ic_launcher.xml
│ └── ic_launcher_round.xml
│ ├── mipmap-hdpi
│ ├── ic_launcher.png
│ ├── ic_launcher_background.png
│ ├── ic_launcher_foreground.png
│ └── ic_launcher_round.png
│ ├── mipmap-mdpi
│ ├── ic_launcher.png
│ ├── ic_launcher_background.png
│ ├── ic_launcher_foreground.png
│ └── ic_launcher_round.png
│ ├── mipmap-xhdpi
│ ├── ic_launcher.png
│ ├── ic_launcher_background.png
│ ├── ic_launcher_foreground.png
│ └── ic_launcher_round.png
│ ├── mipmap-xxhdpi
│ ├── ic_launcher.png
│ ├── ic_launcher_background.png
│ ├── ic_launcher_foreground.png
│ └── ic_launcher_round.png
│ ├── mipmap-xxxhdpi
│ ├── ic_launcher.png
│ ├── ic_launcher_background.png
│ ├── ic_launcher_foreground.png
│ └── ic_launcher_round.png
│ ├── values-round
│ └── strings.xml
│ └── values
│ ├── dimens.xml
│ └── strings.xml
└── settings.gradle
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Built application files
2 | *.apk
3 | *.ap_
4 | *.aab
5 |
6 | # Files for the ART/Dalvik VM
7 | *.dex
8 |
9 | # Java class files
10 | *.class
11 |
12 | # Generated files
13 | bin/
14 | gen/
15 | out/
16 | # Uncomment the following line in case you need and you don't have the release build type files in your app
17 | # release/
18 |
19 | # Gradle files
20 | .gradle/
21 | build/
22 |
23 | # Local configuration file (sdk path, etc)
24 | local.properties
25 |
26 | # Proguard folder generated by Eclipse
27 | proguard/
28 |
29 | # Log Files
30 | *.log
31 |
32 | # Android Studio Navigation editor temp files
33 | .navigation/
34 |
35 | # Android Studio captures folder
36 | captures/
37 |
38 | # IntelliJ
39 | *.iml
40 | .idea/workspace.xml
41 | .idea/tasks.xml
42 | .idea/gradle.xml
43 | .idea/assetWizardSettings.xml
44 | .idea/dictionaries
45 | .idea/libraries
46 | # Android Studio 3 in .gitignore file.
47 | .idea/caches
48 | .idea/modules.xml
49 | # Comment next line if keeping position of elements in Navigation Editor is relevant for you
50 | .idea/navEditor.xml
51 |
52 | # Keystore files
53 | # Uncomment the following lines if you do not want to check your keystore files in.
54 | #*.jks
55 | #*.keystore
56 |
57 | # External native build folder generated in Android Studio 2.2 and later
58 | .externalNativeBuild
59 |
60 | # Google Services (e.g. APIs or Firebase)
61 | # google-services.json
62 |
63 | # Freeline
64 | freeline.py
65 | freeline/
66 | freeline_project_description.json
67 |
68 | # fastlane
69 | fastlane/report.xml
70 | fastlane/Preview.html
71 | fastlane/screenshots
72 | fastlane/test_output
73 | fastlane/readme.md
74 |
75 | # Version control
76 | vcs.xml
77 |
78 | # lint
79 | lint/intermediates/
80 | lint/generated/
81 | lint/outputs/
82 | lint/tmp/
83 | # lint/reports/
84 |
--------------------------------------------------------------------------------
/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 |
--------------------------------------------------------------------------------
/.idea/.name:
--------------------------------------------------------------------------------
1 | moveTrack
--------------------------------------------------------------------------------
/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/jarRepositories.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 abb128
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 | # owoTrackVR and moveTrackVR differences
4 | **moveTrackVR** utilizes un/calibrated sensor data instead of the (Game) Rotation Vector. This approach bypasses any automated calibration algorithms implemented by the phone. Many phones incorporate customized sensor algorithms, including drift correction and custom dead zones, which vary across different devices. Unfortunately, the (Game) Rotation Vector on most phones tends to be unreliable due to these customized algorithms.
5 |
6 | **moveTrackVR** is compatible with all **owoTrackVR** servers!
7 |
8 | 
9 |
10 | ## 🎥 Video Demonstration with a Fairphone - First Edition
11 | [ExMoveTrack2.webm](https://github.com/Timocop/moveTrackVR/assets/22834512/5a5642d6-e2bc-4e15-8ace-cd44cdaf94ef)
12 |
13 |
14 | # moveTrackVR Android Application
15 | This application can be installed on an Android device to connect to [SlimeVR server](https://github.com/SlimeVR/SlimeVR-Server) or [PSMoveServiceEx - Virtual Device Manager](https://github.com/Timocop/PSMoveServiceEx-Virtual-Device-Manager) to replace devices orientation data.
16 |
17 | ## Device Compatibility
18 | All phones with gyroscope, accelerometer, and - optionally - magnetometer.
19 |
20 | This app may also be compatible with some Wear OS devices.
21 |
22 | ## Building
23 | The application can be easily built with Android Studio by opening the project in Android Studio.
24 |
25 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 | buildscript {
3 | repositories {
4 | google()
5 | jcenter()
6 | }
7 | dependencies {
8 | classpath "com.android.tools.build:gradle:4.1.1"
9 |
10 | // NOTE: Do not place your application dependencies here; they belong
11 | // in the individual module build.gradle files
12 | }
13 | }
14 |
15 | allprojects {
16 | repositories {
17 | google()
18 | jcenter()
19 | }
20 | }
21 |
22 | task clean(type: Delete) {
23 | delete rootProject.buildDir
24 | }
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
10 | # When configured, Gradle will run in incubating parallel mode.
11 | # This option should only be used with decoupled projects. More details, visit
12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
13 | # org.gradle.parallel=true
14 | # AndroidX package structure to make it clearer which packages are bundled with the
15 | # Android operating system, and which are packaged with your app"s APK
16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn
17 | android.useAndroidX=true
18 | # Automatically convert third-party libraries to use AndroidX
19 | android.enableJetifier=true
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Timocop/moveTrackVR/c99ab44c9fe1e34622bc63070909e88d7103eb2d/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Sat Nov 21 21:08:38 EET 2020
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-bin.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Attempt to set APP_HOME
10 | # Resolve links: $0 may be a link
11 | PRG="$0"
12 | # Need this for relative symlinks.
13 | while [ -h "$PRG" ] ; do
14 | ls=`ls -ld "$PRG"`
15 | link=`expr "$ls" : '.*-> \(.*\)$'`
16 | if expr "$link" : '/.*' > /dev/null; then
17 | PRG="$link"
18 | else
19 | PRG=`dirname "$PRG"`"/$link"
20 | fi
21 | done
22 | SAVED="`pwd`"
23 | cd "`dirname \"$PRG\"`/" >/dev/null
24 | APP_HOME="`pwd -P`"
25 | cd "$SAVED" >/dev/null
26 |
27 | APP_NAME="Gradle"
28 | APP_BASE_NAME=`basename "$0"`
29 |
30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
31 | DEFAULT_JVM_OPTS=""
32 |
33 | # Use the maximum available, or set MAX_FD != -1 to use that value.
34 | MAX_FD="maximum"
35 |
36 | warn () {
37 | echo "$*"
38 | }
39 |
40 | die () {
41 | echo
42 | echo "$*"
43 | echo
44 | exit 1
45 | }
46 |
47 | # OS specific support (must be 'true' or 'false').
48 | cygwin=false
49 | msys=false
50 | darwin=false
51 | nonstop=false
52 | case "`uname`" in
53 | CYGWIN* )
54 | cygwin=true
55 | ;;
56 | Darwin* )
57 | darwin=true
58 | ;;
59 | MINGW* )
60 | msys=true
61 | ;;
62 | NONSTOP* )
63 | nonstop=true
64 | ;;
65 | esac
66 |
67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
68 |
69 | # Determine the Java command to use to start the JVM.
70 | if [ -n "$JAVA_HOME" ] ; then
71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
72 | # IBM's JDK on AIX uses strange locations for the executables
73 | JAVACMD="$JAVA_HOME/jre/sh/java"
74 | else
75 | JAVACMD="$JAVA_HOME/bin/java"
76 | fi
77 | if [ ! -x "$JAVACMD" ] ; then
78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
79 |
80 | Please set the JAVA_HOME variable in your environment to match the
81 | location of your Java installation."
82 | fi
83 | else
84 | JAVACMD="java"
85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
86 |
87 | Please set the JAVA_HOME variable in your environment to match the
88 | location of your Java installation."
89 | fi
90 |
91 | # Increase the maximum file descriptors if we can.
92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
93 | MAX_FD_LIMIT=`ulimit -H -n`
94 | if [ $? -eq 0 ] ; then
95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
96 | MAX_FD="$MAX_FD_LIMIT"
97 | fi
98 | ulimit -n $MAX_FD
99 | if [ $? -ne 0 ] ; then
100 | warn "Could not set maximum file descriptor limit: $MAX_FD"
101 | fi
102 | else
103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
104 | fi
105 | fi
106 |
107 | # For Darwin, add options to specify how the application appears in the dock
108 | if $darwin; then
109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
110 | fi
111 |
112 | # For Cygwin, switch paths to Windows format before running java
113 | if $cygwin ; then
114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
116 | JAVACMD=`cygpath --unix "$JAVACMD"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Escape application args
158 | save () {
159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
160 | echo " "
161 | }
162 | APP_ARGS=$(save "$@")
163 |
164 | # Collect all arguments for the java command, following the shell quoting and substitution rules
165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
166 |
167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
169 | cd "$(dirname "$0")"
170 | fi
171 |
172 | exec "$JAVACMD" "$@"
173 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS=
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 |
53 | :win9xME_args
54 | @rem Slurp the command line arguments.
55 | set CMD_LINE_ARGS=
56 | set _SKIP=2
57 |
58 | :win9xME_args_slurp
59 | if "x%~1" == "x" goto execute
60 |
61 | set CMD_LINE_ARGS=%*
62 |
63 | :execute
64 | @rem Setup the command line
65 |
66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
67 |
68 | @rem Execute Gradle
69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
70 |
71 | :end
72 | @rem End local scope for the variables with windows NT shell
73 | if "%ERRORLEVEL%"=="0" goto mainEnd
74 |
75 | :fail
76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
77 | rem the _cmd.exe /c_ return code!
78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
79 | exit /b 1
80 |
81 | :mainEnd
82 | if "%OS%"=="Windows_NT" endlocal
83 |
84 | :omega
85 |
--------------------------------------------------------------------------------
/moveTrackLib/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/moveTrackLib/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'com.android.library'
3 | }
4 |
5 | android {
6 | compileSdkVersion 30
7 | buildToolsVersion "30.0.2"
8 |
9 | defaultConfig {
10 | minSdkVersion 16
11 | targetSdkVersion 30
12 | versionCode 17
13 | versionName '9.5.5'
14 |
15 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
16 | }
17 |
18 | buildTypes {
19 | release {
20 | minifyEnabled false
21 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
22 | }
23 | }
24 | compileOptions {
25 | sourceCompatibility JavaVersion.VERSION_1_8
26 | targetCompatibility JavaVersion.VERSION_1_8
27 | }
28 | }
29 |
30 | dependencies {
31 |
32 | implementation 'androidx.appcompat:appcompat:1.1.0'
33 | implementation 'com.google.android.material:material:1.1.0'
34 | implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
35 | implementation 'androidx.legacy:legacy-support-v4:1.0.0'
36 |
37 | def nav_version = "2.3.1"
38 |
39 | // Java language implementation
40 | implementation "androidx.navigation:navigation-fragment:$nav_version"
41 | implementation "androidx.navigation:navigation-ui:$nav_version"
42 |
43 | // Feature module Support
44 | implementation "androidx.navigation:navigation-dynamic-features-fragment:$nav_version"
45 |
46 | implementation 'androidx.localbroadcastmanager:localbroadcastmanager:1.0.0'
47 | }
--------------------------------------------------------------------------------
/moveTrackLib/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
--------------------------------------------------------------------------------
/moveTrackLib/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/moveTrackLib/src/main/ic_launcher-playstore.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Timocop/moveTrackVR/c99ab44c9fe1e34622bc63070909e88d7103eb2d/moveTrackLib/src/main/ic_launcher-playstore.png
--------------------------------------------------------------------------------
/moveTrackLib/src/main/java/org/moveTrack/AppStatus.java:
--------------------------------------------------------------------------------
1 | package org.moveTrack;
2 |
3 | import android.app.Activity;
4 | import android.app.Service;
5 | import android.content.Intent;
6 | import android.widget.TextView;
7 |
8 | import androidx.localbroadcastmanager.content.LocalBroadcastManager;
9 |
10 | public class AppStatus {
11 | public String statusi = "";
12 | private Activity main_activity;
13 | private TextView statusLbl;
14 | private Service main_service;
15 |
16 | public AppStatus(Activity act, TextView tx) {
17 | main_activity = act;
18 | statusLbl = tx;
19 | main_service = null;
20 | }
21 |
22 | AppStatus(Service act) {
23 | main_service = act;
24 | update("Service Initialized");
25 | }
26 |
27 | AppStatus() {
28 | main_activity = null;
29 | statusLbl = null;
30 | }
31 |
32 | public void update(String to) {
33 | statusi = to + "\n" + statusi;
34 | if (main_service != null) {
35 | Intent intent = new Intent("info-log");
36 | intent.putExtra("message", to);
37 | LocalBroadcastManager.getInstance(main_service).sendBroadcast(intent);
38 | return;
39 | }
40 | if ((main_activity == null) || (statusLbl == null)) {
41 | return;
42 | }
43 | main_activity.runOnUiThread(() -> {
44 | statusLbl.setText(statusi);
45 | });
46 |
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/moveTrackLib/src/main/java/org/moveTrack/AutoDiscoverer.java:
--------------------------------------------------------------------------------
1 | package org.moveTrack;
2 |
3 | import android.app.Activity;
4 | import android.content.DialogInterface;
5 | import android.content.Intent;
6 | import android.os.Build;
7 | import android.view.WindowManager;
8 |
9 | import androidx.appcompat.app.AlertDialog;
10 |
11 | import java.net.DatagramPacket;
12 | import java.net.DatagramSocket;
13 | import java.net.InetAddress;
14 | import java.net.SocketTimeoutException;
15 | import java.nio.ByteBuffer;
16 |
17 |
18 | public class AutoDiscoverer {
19 | static final int port = 35903;
20 | //static final String mcastAddress = "234.35.90.3";
21 | // VPNs on Android will cause some issues with multicast, need to just broadcast :(
22 | static final String mcastAddress = "255.255.255.255";
23 | public static boolean discoveryStillNecessary = true;
24 | public static boolean dialogShown = false;
25 | Activity act;
26 | ConfigSaver onConnect;
27 | public AutoDiscoverer(Activity c, ConfigSaver onYes) {
28 | act = c;
29 | onConnect = onYes;
30 | }
31 |
32 | private static DiscoveryResult attempt_discover_infoserver(int timeout) {
33 | try {
34 | DatagramSocket socket = new DatagramSocket();
35 | {
36 | String handshake = "DISCOVERY";
37 | DatagramPacket packet = new DatagramPacket(handshake.getBytes(), handshake.length(),
38 | InetAddress.getByName(mcastAddress), port);
39 |
40 | socket.send(packet);
41 |
42 | socket.setBroadcast(true);
43 |
44 | ByteBuffer buff = ByteBuffer.allocate(128);
45 | DatagramPacket pkt = new DatagramPacket(buff.array(), buff.capacity());
46 | socket.setSoTimeout(timeout);
47 | socket.receive(pkt);
48 |
49 |
50 | String response = new String(buff.array());
51 |
52 |
53 | for (String line : response.split("\n")) {
54 | try {
55 | int port = Integer.parseInt(line.split(":")[0]);
56 | String name = line.split(":")[1];
57 |
58 | if (port > 0) {
59 | //discoveryStillNecessary = false;
60 | //alert(pkt.getAddress(), port, name);
61 | return DiscoveryResult.some(pkt.getAddress(), port, name);
62 | }
63 | } catch (NumberFormatException ignored) {
64 | }
65 | }
66 | }
67 | } catch (SocketTimeoutException ignored) {
68 | } catch (Exception e) {
69 | e.printStackTrace();
70 | }
71 |
72 | return DiscoveryResult.none();
73 | }
74 |
75 | public static DiscoveryResult attempt_discover(int timeout) {
76 | DiscoveryResult info_result = attempt_discover_infoserver(timeout);
77 | if (info_result.found) return info_result;
78 |
79 | return DiscoveryResult.none();
80 | }
81 |
82 | private void plsDoConnect(InetAddress addr, int port) {
83 | Intent mainIntent = new Intent(act, TrackingService.class);
84 | mainIntent.putExtra("ipAddrTxt", addr.getHostAddress());
85 | mainIntent.putExtra("port_no", port);
86 |
87 | ConfigSettings configSettings = onConnect.saveLoad(addr.getHostAddress(), port);
88 |
89 | mainIntent.putExtra("magnetometer", configSettings.magnetometerEnabled);
90 | mainIntent.putExtra("madgwickbeta", configSettings.madgwickBeta);
91 | mainIntent.putExtra("stabilization", configSettings.stabilization);
92 | mainIntent.putExtra("sensordata", configSettings.sensorData);
93 | mainIntent.putExtra("smartcorrection", configSettings.smartCorrection);
94 |
95 | // start service
96 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
97 | act.startForegroundService(mainIntent);
98 | } else {
99 | act.startService(mainIntent);
100 | }
101 | }
102 |
103 | private void alert(InetAddress addr, int port, String name) {
104 | dialogShown = true;
105 | act.runOnUiThread(() -> {
106 | try {
107 | AlertDialog.Builder alert = new AlertDialog.Builder(act);
108 | alert.setTitle("Automatic Discovery");
109 | alert.setMessage("Connect to " + addr.getHostAddress() + ":" + String.valueOf(port) + " (" + name + ")?");
110 |
111 | alert.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
112 | public void onClick(DialogInterface dialog, int whichButton) {
113 | plsDoConnect(addr, port);
114 | }
115 | });
116 |
117 | alert.setNegativeButton("No", new DialogInterface.OnClickListener() {
118 | public void onClick(DialogInterface dialog, int whichButton) {
119 | }
120 | });
121 |
122 | alert.show();
123 | } catch (WindowManager.BadTokenException ignored) {
124 | }
125 | });
126 | }
127 |
128 | public void try_discover() {
129 | while (discoveryStillNecessary) {
130 | DiscoveryResult result = attempt_discover(5000);
131 |
132 | if (result.found) {
133 | discoveryStillNecessary = false;
134 | alert(result.server_address, result.port, result.name);
135 | break;
136 | }
137 | }
138 | }
139 |
140 |
141 | public interface ConfigSaver {
142 | ConfigSettings saveLoad(String ip_addr, int port);
143 | }
144 |
145 | public static class ConfigSettings {
146 | public boolean magnetometerEnabled;
147 | public float madgwickBeta;
148 | public boolean stabilization;
149 | public int sensorData;
150 | public boolean smartCorrection;
151 | }
152 |
153 | public static class DiscoveryResult {
154 | public boolean found;
155 |
156 | public InetAddress server_address;
157 | public int port;
158 |
159 | public String name;
160 |
161 | DiscoveryResult() {
162 | }
163 |
164 | public static DiscoveryResult none() {
165 | DiscoveryResult result = new DiscoveryResult();
166 | result.found = false;
167 |
168 | return result;
169 | }
170 |
171 | public static DiscoveryResult some(InetAddress srv, int port, String name) {
172 | DiscoveryResult result = new DiscoveryResult();
173 | result.found = true;
174 | result.server_address = srv;
175 | result.port = port;
176 | result.name = name;
177 |
178 | return result;
179 | }
180 | }
181 |
182 | }
183 |
--------------------------------------------------------------------------------
/moveTrackLib/src/main/java/org/moveTrack/GyroListener.java:
--------------------------------------------------------------------------------
1 | package org.moveTrack;
2 |
3 | import android.hardware.Sensor;
4 | import android.hardware.SensorEvent;
5 | import android.hardware.SensorEventListener;
6 | import android.hardware.SensorManager;
7 | import android.os.Handler;
8 | import android.util.Log;
9 |
10 | import org.moveTrack.math.MadgwickAHRS;
11 | import org.moveTrack.math.Quaternion;
12 | import org.moveTrack.math.Vector3;
13 |
14 | public class GyroListener implements SensorEventListener {
15 | private static final float NS2S = 1.0f / 1000000000.0f;
16 |
17 | private static final long MADGWICK_UPDATE_RATE_MS = 5;
18 | private static final long MADGWICK_SMARTRESET_MS = 2000;
19 | private static final float MADGWICK_SMARTRESET_GRAV_STABLE = 0.25f;
20 | private static final float MADGWICK_SMARTRESET_DEG_MIN = 5.0f;
21 | private static final float MADGWICK_SMARTRESET_DEG_MAX = 25.0f;
22 | private static final boolean MADGWICK_SMARTRESET_INSTANT = true;
23 |
24 | private static final float STABILIZATION_GYRO_MAX_DEG = 1.f;
25 | private static final float STABILIZATION_GYRO_MIN_DEG = 0.1f;
26 |
27 | public final static boolean OPTIMIZE_ROTATION_PACKET_SEND = true;
28 |
29 |
30 | UDPGyroProviderClient udpClient;
31 | private SensorManager sensorManager;
32 | private Sensor GyroSensor;
33 | private Sensor AccelSensor;
34 | private Sensor MagSensor;
35 |
36 | Quaternion rot_vec;
37 | private float[] gyro_vec;
38 | private float[] accel_vec;
39 | private float[] gav_vec;
40 | private float[] lin_accel_vec;
41 | private float[] mag_vec;
42 |
43 | private long last_send_timestamp;
44 | private long last_madgwick_timestamp;
45 | private long last_gyro_timestamp;
46 | private long elapsed_gyro_time;
47 | private int ROTATION_SENSOR_TYPE;
48 | private String sensor_type = "";
49 | private MadgwickAHRS filter_madgwick;
50 | private MadgwickAHRS filter_madgwick_quick;
51 | private float madgwick_beta;
52 | private boolean madgwick_reset;
53 |
54 | private boolean use_stabilization;
55 | private boolean use_smartcorrection;
56 | private float smartcorrection_time;
57 | private int sensor_data;
58 | private Handler mHandler;
59 |
60 | GyroListener(SensorManager manager, UDPGyroProviderClient udpClient_v, AppStatus logger, AutoDiscoverer.ConfigSettings configSettings) throws Exception {
61 | sensorManager = manager;
62 |
63 | GyroSensor = sensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE);
64 | if (GyroSensor == null) {
65 | GyroSensor = sensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE_UNCALIBRATED);
66 | if (GyroSensor == null) {
67 | logger.update("Gyroscope sensor could not be found, this data will be unavailable.");
68 | } else {
69 | logger.update("Uncalibrated gyroscope sensor found! Might cause sensor drift!");
70 | }
71 | } else {
72 | logger.update("Gyroscope sensor found!");
73 | }
74 |
75 | AccelSensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
76 | if (AccelSensor == null) {
77 | AccelSensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER_UNCALIBRATED);
78 | if (AccelSensor == null) {
79 | logger.update("Accelerometer sensor could not be found, this data will be unavailable.");
80 | } else {
81 | logger.update("Uncalibrated accelerometer sensor found! Might cause sensor drift!");
82 | }
83 | } else {
84 | logger.update("Accelerometer sensor found!");
85 | }
86 |
87 | if (configSettings.magnetometerEnabled) {
88 | MagSensor = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
89 | if (MagSensor == null) {
90 | logger.update("Magnetometer sensor could not be found, this data will be unavailable.");
91 | } else {
92 | logger.update("Magnetometer sensor found!");
93 | }
94 | } else {
95 | logger.update("Magnetometer disabled by user!");
96 | }
97 |
98 | madgwick_beta = configSettings.madgwickBeta;
99 | if (madgwick_beta < 0.0f)
100 | madgwick_beta = 0.0f;
101 | if (madgwick_beta > 1.0f)
102 | madgwick_beta = 1.0f;
103 |
104 | madgwick_reset = false;
105 | use_stabilization = configSettings.stabilization;
106 | sensor_data = configSettings.sensorData;
107 | use_smartcorrection = configSettings.smartCorrection;
108 | smartcorrection_time = 0.0f;
109 |
110 | rot_vec = new Quaternion(0.0,0.0,0.0,1.0);
111 | gyro_vec = new float[3];
112 | accel_vec = new float[3];
113 | gav_vec = new float[3];
114 | lin_accel_vec = new float[3];
115 | mag_vec = new float[3];
116 | last_gyro_timestamp = 0;
117 | last_madgwick_timestamp = 0;
118 | last_send_timestamp = 0;
119 | elapsed_gyro_time = 0;
120 | filter_madgwick = new MadgwickAHRS(0.0f, madgwick_beta);
121 | filter_madgwick_quick = new MadgwickAHRS(0.0f, 0.2f);
122 |
123 | udpClient = udpClient_v;
124 | udpClient.set_listener(this);
125 | }
126 |
127 | public void register_listeners() {
128 | mHandler = new Handler();
129 | sensorManager.registerListener(this, GyroSensor, SensorManager.SENSOR_DELAY_FASTEST, mHandler);
130 | sensorManager.registerListener(this, AccelSensor, SensorManager.SENSOR_DELAY_FASTEST, mHandler);
131 | sensorManager.registerListener(this, MagSensor, SensorManager.SENSOR_DELAY_FASTEST, mHandler);
132 | }
133 |
134 | public void stop() {
135 | sensorManager.unregisterListener(this);
136 | }
137 |
138 | @Override
139 | public void onSensorChanged(SensorEvent event) {
140 | if (event.timestamp == 0)
141 | return;
142 |
143 | if (event.sensor.getType() == Sensor.TYPE_GYROSCOPE
144 | || event.sensor.getType() == Sensor.TYPE_GYROSCOPE_UNCALIBRATED) {
145 | float[] vec = new float[3];
146 | vec[0] = event.values[0];
147 | vec[1] = event.values[1];
148 | vec[2] = event.values[2];
149 |
150 | if (last_gyro_timestamp != 0) {
151 | final float gyroDelta = (event.timestamp - last_gyro_timestamp) * NS2S;
152 |
153 | gyro_vec[0] += vec[0] * gyroDelta;
154 | gyro_vec[1] += vec[1] * gyroDelta;
155 | gyro_vec[2] += vec[2] * gyroDelta;
156 |
157 | if ((event.timestamp - elapsed_gyro_time) * NS2S > MADGWICK_UPDATE_RATE_MS / 1000.0f) {
158 | float totalTime = (event.timestamp - elapsed_gyro_time) * NS2S;
159 |
160 | gyro_vec[0] /= totalTime;
161 | gyro_vec[1] /= totalTime;
162 | gyro_vec[2] /= totalTime;
163 |
164 | switch(sensor_data) {
165 | case 0:
166 | // Send nothing
167 | break;
168 | case 1:
169 | // Send minimal (compat owoTrack servers)
170 | udpClient.provide_owo_gyro(event.timestamp, gyro_vec);
171 | break;
172 | case 2:
173 | if (event.sensor.getType() == Sensor.TYPE_GYROSCOPE) {
174 | udpClient.provide_gyro(event.timestamp, gyro_vec);
175 | }
176 | else {
177 | udpClient.provide_uncalib_gyro(event.timestamp, gyro_vec);
178 | }
179 | break;
180 | }
181 |
182 | updateMadgwick(event.timestamp);
183 | elapsed_gyro_time = event.timestamp;
184 |
185 | gyro_vec[0] = 0.f;
186 | gyro_vec[1] = 0.f;
187 | gyro_vec[2] = 0.f;
188 | }
189 | }
190 |
191 | last_gyro_timestamp = event.timestamp;
192 |
193 | } else if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER
194 | || event.sensor.getType() == Sensor.TYPE_ACCELEROMETER_UNCALIBRATED) {
195 | float[] vec = new float[3];
196 | vec[0] = event.values[0];
197 | vec[1] = event.values[1];
198 | vec[2] = event.values[2];
199 |
200 | {
201 | final float alpha = 0.8f;
202 |
203 | gav_vec[0] = lowpass_filter(alpha, gav_vec[0], vec[0]);
204 | gav_vec[1] = lowpass_filter(alpha, gav_vec[1], vec[1]);
205 | gav_vec[2] = lowpass_filter(alpha, gav_vec[2], vec[2]);
206 |
207 | lin_accel_vec[0] = vec[0] - gav_vec[0];
208 | lin_accel_vec[1] = vec[1] - gav_vec[1];
209 | lin_accel_vec[2] = vec[2] - gav_vec[2];
210 | }
211 |
212 | accel_vec = vec;
213 |
214 | switch(sensor_data) {
215 | case 0:
216 | // Send nothing
217 | break;
218 | case 1:
219 | // Send minimal (compat owoTrack servers)
220 | udpClient.provide_owo_accel(event.timestamp, lin_accel_vec);
221 | break;
222 | case 2:
223 | if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
224 | udpClient.provide_accel(event.timestamp, vec);
225 | }
226 | else {
227 | udpClient.provide_uncalib_accel(event.timestamp, vec);
228 | }
229 | break;
230 | }
231 |
232 | } else if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD
233 | || event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD_UNCALIBRATED) {
234 | float[] vec = new float[3];
235 | vec[0] = event.values[0];
236 | vec[1] = event.values[1];
237 | vec[2] = event.values[2];
238 |
239 | mag_vec = vec;
240 |
241 | switch(sensor_data) {
242 | case 0:
243 | // Send nothing
244 | break;
245 | case 1:
246 | // Send minimal (compat owoTrack servers)
247 | break;
248 | case 2:
249 | if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) {
250 | udpClient.provide_mag(event.timestamp, vec);
251 | }
252 | else {
253 | udpClient.provide_uncalib_mag(event.timestamp, vec);
254 | }
255 | break;
256 | }
257 | }
258 | }
259 |
260 | private void updateMadgwick(long timeStamp) {
261 | if (last_madgwick_timestamp != 0) {
262 | final float deltaTime = (timeStamp - last_madgwick_timestamp) * NS2S;
263 |
264 | { // Main adgwick
265 | float beta;
266 |
267 | if (madgwick_reset) {
268 | beta = 0.9f;
269 | }
270 | else {
271 | beta = getAdaptiveBeta(deltaTime);
272 | }
273 |
274 | final float old_beta = filter_madgwick.getBeta();
275 | final float beta_smooth = lowpass_filter(0.1f, old_beta, beta);
276 |
277 | filter_madgwick.setBeta(beta_smooth);
278 | filter_madgwick.setSamplePeriod(deltaTime);
279 |
280 | if (MagSensor != null) {
281 | filter_madgwick.update(
282 | gyro_vec[0], gyro_vec[1], gyro_vec[2],
283 | accel_vec[0], accel_vec[1], accel_vec[2],
284 | mag_vec[0], mag_vec[1], mag_vec[2]);
285 | } else {
286 | filter_madgwick.update(
287 | gyro_vec[0], gyro_vec[1], gyro_vec[2],
288 | accel_vec[0], accel_vec[1], accel_vec[2]);
289 | }
290 | }
291 |
292 | if (use_smartcorrection) { // Quick Madgwick
293 | filter_madgwick_quick.setSamplePeriod(deltaTime);
294 |
295 | if (MagSensor != null) {
296 | filter_madgwick_quick.update(
297 | gyro_vec[0], gyro_vec[1], gyro_vec[2],
298 | accel_vec[0], accel_vec[1], accel_vec[2],
299 | mag_vec[0], mag_vec[1], mag_vec[2]);
300 | } else {
301 | filter_madgwick_quick.update(
302 | gyro_vec[0], gyro_vec[1], gyro_vec[2],
303 | accel_vec[0], accel_vec[1], accel_vec[2]);
304 | }
305 | }
306 |
307 | float[] quat = filter_madgwick.getQuaternion();
308 | float[] quat2 = filter_madgwick_quick.getQuaternion();
309 | Quaternion swapQuat = new Quaternion(
310 | quat[1],
311 | quat[2],
312 | quat[3],
313 | quat[0]
314 | );
315 | Quaternion swapQuat2 = new Quaternion(
316 | quat2[1],
317 | quat2[2],
318 | quat2[3],
319 | quat2[0]
320 | );
321 |
322 | float accel_g = 1.0f + (float)Math.sqrt(
323 | lin_accel_vec[0] * lin_accel_vec[0] +
324 | lin_accel_vec[1] * lin_accel_vec[1] +
325 | lin_accel_vec[2] * lin_accel_vec[2]);
326 |
327 | // If angle difference is too big, attempt to quick reset.
328 | if (use_smartcorrection) {
329 | if (madgwick_reset) {
330 | // Stop when deviation is too small
331 | if (Math.abs(calculateQuaternionAngle(swapQuat, swapQuat2)) < MADGWICK_SMARTRESET_DEG_MIN) {
332 | madgwick_reset = false;
333 | }
334 |
335 | // Stop if gravity is unstable
336 | if (accel_g > MADGWICK_SMARTRESET_GRAV_STABLE && accel_g < 1.f + (1.f - MADGWICK_SMARTRESET_GRAV_STABLE)) {
337 | madgwick_reset = false;
338 | }
339 | }
340 | else {
341 | if (Math.abs(calculateQuaternionAngle(swapQuat, swapQuat2)) > MADGWICK_SMARTRESET_DEG_MAX) {
342 | // Make sure smart madgwick its kind of stable
343 | if (accel_g > MADGWICK_SMARTRESET_GRAV_STABLE && accel_g < 1.f + (1.f - MADGWICK_SMARTRESET_GRAV_STABLE)) {
344 | smartcorrection_time += deltaTime;
345 |
346 | if (smartcorrection_time > (MADGWICK_SMARTRESET_MS / 1000.f)) {
347 | if (MADGWICK_SMARTRESET_INSTANT) {
348 | swapQuat = new Quaternion(swapQuat2);
349 | smartcorrection_time = 0.0f;
350 |
351 | filter_madgwick.setQuaternion(
352 | (float)swapQuat.getW(),
353 | (float)swapQuat.getX(),
354 | (float)swapQuat.getY(),
355 | (float)swapQuat.getZ());
356 | }
357 | else {
358 | madgwick_reset = true;
359 | }
360 | }
361 | }
362 | else {
363 | if (smartcorrection_time > 0.0f)
364 | smartcorrection_time = 0.0f;
365 | }
366 | }
367 | else {
368 | if (smartcorrection_time > 0.0f)
369 | smartcorrection_time = 0.0f;
370 | }
371 | }
372 | }
373 | else {
374 | if (madgwick_reset)
375 | madgwick_reset = false;
376 | }
377 |
378 | // For some reason ROTATION_VECTOR quaternion and MADGWICK quaternion have a 90° yaw difference.
379 | // Add a 90° offset to make it compatible with owoTrack servers.
380 | swapQuat = new Quaternion(new Vector3(0.f, 0.f, 1.f), 90.f * (Math.PI / 180.f)).mulThis(swapQuat);
381 | float[] newQuat = new float[4];
382 | newQuat[0] = (float) swapQuat.getX();
383 | newQuat[1] = (float) swapQuat.getY();
384 | newQuat[2] = (float) swapQuat.getZ();
385 | newQuat[3] = (float) swapQuat.getW();
386 |
387 | // Keep alive
388 | final float last_send = (timeStamp - last_send_timestamp) * NS2S;
389 |
390 | if (!OPTIMIZE_ROTATION_PACKET_SEND || last_send > 0.5f || !quat_equal(swapQuat, rot_vec)) {
391 | udpClient.provide_rot(timeStamp, newQuat);
392 | last_send_timestamp = timeStamp;
393 |
394 | rot_vec = swapQuat;
395 | }
396 | }
397 |
398 | last_madgwick_timestamp = timeStamp;
399 | }
400 |
401 | private boolean quat_equal(Quaternion q1, Quaternion q2)
402 | {
403 | final float EQUAL_TOLERANCE = 0.0001f;
404 |
405 | if (Math.abs(q1.getX() - q2.getX()) < EQUAL_TOLERANCE &&
406 | Math.abs(q1.getY() - q2.getY()) < EQUAL_TOLERANCE &&
407 | Math.abs(q1.getZ() - q2.getZ()) < EQUAL_TOLERANCE &&
408 | Math.abs(q1.getW() - q2.getW()) < EQUAL_TOLERANCE) {
409 | return true;
410 | }
411 |
412 | return false;
413 | }
414 |
415 | private float getAdaptiveBeta(float deltaTime) {
416 | float beta = madgwick_beta;
417 |
418 | if (!use_stabilization) {
419 | // Do not allow no drift correction
420 | if (beta < 0.01f)
421 | beta = 0.01f;
422 |
423 | return beta;
424 | }
425 |
426 | float gyro_sq = (float) Math.sqrt(gyro_vec[0] * gyro_vec[0] + gyro_vec[1] * gyro_vec[1] + gyro_vec[2] * gyro_vec[2]) * deltaTime;
427 | gyro_sq = (float) (gyro_sq * (180.f / Math.PI));
428 |
429 | float beta_multi = ((gyro_sq - STABILIZATION_GYRO_MIN_DEG) / STABILIZATION_GYRO_MAX_DEG);
430 | if (beta_multi < 0.0f)
431 | beta_multi = 0.f;
432 | if (beta_multi > 1.0f)
433 | beta_multi = 1.f;
434 |
435 | return (beta * beta_multi);
436 | }
437 |
438 |
439 | private float lowpass_filter(float alpha, float old_val, float new_val)
440 | {
441 | return alpha * new_val + (1.f - alpha) * old_val;
442 | }
443 |
444 | private double calculateQuaternionAngle(Quaternion q1, Quaternion q2) {
445 | q1.normalizeThis();
446 | q2.normalizeThis();
447 |
448 | float dotProduct = (float)(q1.getX() * q2.getX() + q1.getY() * q2.getY() + q1.getZ() * q2.getZ() + q1.getW() * q2.getW());
449 | float angle = (float)(2 * Math.acos(Math.abs(dotProduct)));
450 |
451 | return Math.toDegrees(angle);
452 | }
453 |
454 | @Override
455 | public void onAccuracyChanged(Sensor sensor, int accuracy) {
456 | //magnetometerAccuracy = accuracy;
457 | //if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH) {
458 | // System.out.println("@@@ Accuracy for " + sensor.getStringType() + " : " + String.valueOf(accuracy));
459 | //}
460 |
461 | //udpClient.provide_accuracy(accuracy);
462 | }
463 | }
464 |
--------------------------------------------------------------------------------
/moveTrackLib/src/main/java/org/moveTrack/Handshaker.java:
--------------------------------------------------------------------------------
1 | package org.moveTrack;
2 |
3 | import java.io.IOException;
4 | import java.net.DatagramPacket;
5 | import java.net.DatagramSocket;
6 | import java.net.InetAddress;
7 | import java.net.PortUnreachableException;
8 | import java.net.SocketTimeoutException;
9 | import java.nio.ByteBuffer;
10 | import java.util.Arrays;
11 |
12 | class HandshakeFailException extends Exception {
13 | public HandshakeFailException(String s) {
14 | super(s);
15 | }
16 | }
17 |
18 | public class Handshaker {
19 | // Android doesn't allow getting MAC address anymore, so we fake one
20 | // NOTE: A random mac gets generated and set by MainActivity using the
21 | // setMac method below, this is not a constant value. It's random per-device
22 | private static byte[] pseudo_mac = new byte[]{0, 69, 0, 0, 0, 0};
23 |
24 | public static void setMac(long from) {
25 | ByteBuffer from_b = ByteBuffer.allocate(Long.BYTES);
26 | from_b.putLong(from);
27 |
28 | byte[] bytes = from_b.array();
29 |
30 | for (int i = 0; i < Math.min(bytes.length, pseudo_mac.length); i++) {
31 | pseudo_mac[i] = bytes[i];
32 | }
33 | }
34 |
35 | private static byte[] getMac(){
36 | return pseudo_mac;
37 | }
38 |
39 |
40 | public static void insert_slime_info(ByteBuffer buff) {
41 | final int boardType = 13;
42 | final int imuType = 0;
43 | final int mcuType = 3;
44 |
45 | final int[] imuInfo = {0, 0, 0};
46 |
47 | final int firmwareBuild = 8;
48 |
49 | final byte[] firmware = {'o', 'w', 'o', 'T', 'r', 'a', 'c', 'k', '8'}; // 9 bytes
50 |
51 | buff.putInt(boardType); // 4 bytes
52 | buff.putInt(imuType); // 4 bytes
53 | buff.putInt(mcuType); // 4 bytes
54 |
55 | // 4 * 3 = 12 bytes
56 | for (int info : imuInfo) buff.putInt(info);
57 |
58 | buff.putInt(firmwareBuild); // 4 bytes
59 |
60 | buff.put((byte) firmware.length); // 1 bytes
61 | buff.put(firmware);
62 |
63 | byte[] mac = getMac();
64 | assert (mac.length == 6);
65 | buff.put(mac); // 6 bytes
66 |
67 | buff.put((byte) 0xFF); // top it off
68 | }
69 |
70 | public static HandshakeResult try_handshake(DatagramSocket socket, InetAddress ip, int port) throws HandshakeFailException {
71 | //if(ip.toString().endsWith(".255")) return true;
72 |
73 | byte[] buffer = new byte[64];
74 | DatagramPacket handshake_receive = new DatagramPacket(buffer, 64);
75 |
76 |
77 | int tries = 0;
78 | boolean tryBroadcast = false;
79 | while (true) {
80 | int len = 12;
81 |
82 | // if the user is running an old version of owoTrackVR driver,
83 | // recvfrom() will fail as the max packet length the old driver
84 | // supported was around 28 bytes. to maintain backwards
85 | // compatibility the slime extensions are not sent after a
86 | // certain number of failures
87 | boolean sendSlimeExtensions = (tries < 10);
88 | if (sendSlimeExtensions) len += 36 + 9;
89 |
90 | ByteBuffer handshake_buff = ByteBuffer.allocate(len);
91 | handshake_buff.putInt(3);
92 | handshake_buff.putLong(0);
93 |
94 | if (sendSlimeExtensions) {
95 | try {
96 | insert_slime_info(handshake_buff); // 36 extra bytes
97 | } catch (Exception e) {
98 | e.printStackTrace();
99 | }
100 | }
101 |
102 | tries++;
103 | tryBroadcast = tryBroadcast || (tries > 4);
104 | if (tries > 12) {
105 | throw new HandshakeFailException("Connection failed. Ensure IP and port are correct, that the server is running and not blocked by Windows Firewall (try changing your network type to private in Windows) or blocked by router, and that you're connected to the same network (you may need to disable Mobile Data)");
106 | }
107 |
108 | try {
109 | if (socket == null) throw new HandshakeFailException("Socket is null!");
110 |
111 | if (!tryBroadcast) {
112 | socket.send(new DatagramPacket(handshake_buff.array(), len, ip, port));
113 | } else {
114 | socket.disconnect();
115 | socket.setBroadcast(true);
116 | InetAddress broadcast_address = InetAddress.getByName("255.255.255.255");
117 | socket.send(new DatagramPacket(handshake_buff.array(), len, broadcast_address, 6969));
118 | }
119 |
120 | try {
121 | socket.setSoTimeout(250);
122 | socket.receive(handshake_receive);
123 |
124 | if (buffer[0] != 3) {
125 | throw new HandshakeFailException("Handshake failed, the server did not respond correctly. Ensure everything is up-to-date and that the port is correct.");
126 | }
127 |
128 | String result = new String(
129 | Arrays.copyOfRange(buffer, 1, 64),
130 | "ASCII");
131 |
132 | result = result.substring(0, result.indexOf(0));
133 |
134 | if (!result.startsWith("Hey OVR =D")) {
135 | throw new HandshakeFailException("Handshake failed, the server did not respond correctly in the header. Ensure everything is up-to-date and that the port is correct");
136 | }
137 |
138 | int version = -1;
139 | try {
140 | version = Integer.parseInt(result.substring(11));
141 | } catch (NumberFormatException e) {
142 | throw new HandshakeFailException("Handshake failed, server did not send an int");
143 | }
144 |
145 | if (version != UDPGyroProviderClient.CURRENT_VERSION) {
146 | throw new HandshakeFailException("Handshake failed, mismatching version"
147 | + "\nServer version: " + String.valueOf(version)
148 | + "\nClient version: " + String.valueOf(UDPGyroProviderClient.CURRENT_VERSION)
149 | + "\nPlease make sure everything is up to date.");
150 | }
151 |
152 | boolean had_to_rediscover = (handshake_receive.getAddress() != ip) || (handshake_receive.getPort() != port);
153 | if (tryBroadcast && had_to_rediscover) {
154 | socket.connect(handshake_receive.getAddress(), handshake_receive.getPort());
155 | socket.setBroadcast(false);
156 | }
157 | return HandshakeResult.some(handshake_receive.getAddress(), handshake_receive.getPort(), had_to_rediscover);
158 | } catch (SocketTimeoutException e) {
159 | continue;
160 | }
161 | } catch (PortUnreachableException e) {
162 | //throw new HandshakeFailException("Port is unreachable. Ensure that you've entered the correct IP and port, that the server is running and that you're on the same wifi network as the computer.");
163 | tryBroadcast = true;
164 | continue;
165 | } catch (IOException e) {
166 | throw new HandshakeFailException("Handshake IO exception: " + e.toString());
167 | }
168 | }
169 | }
170 |
171 | public static class HandshakeResult {
172 | public boolean success;
173 |
174 | public boolean had_to_rediscover;
175 | public InetAddress server_address;
176 | public int port;
177 |
178 | HandshakeResult() {
179 | }
180 |
181 | public static Handshaker.HandshakeResult none() {
182 | Handshaker.HandshakeResult result = new Handshaker.HandshakeResult();
183 | result.success = false;
184 |
185 | return result;
186 | }
187 |
188 | public static Handshaker.HandshakeResult some(InetAddress srv, int port, boolean had_to_rediscover) {
189 | Handshaker.HandshakeResult result = new Handshaker.HandshakeResult();
190 | result.success = true;
191 | result.server_address = srv;
192 | result.port = port;
193 | result.had_to_rediscover = had_to_rediscover;
194 |
195 | return result;
196 | }
197 | }
198 | }
199 |
--------------------------------------------------------------------------------
/moveTrackLib/src/main/java/org/moveTrack/TrackingService.java:
--------------------------------------------------------------------------------
1 | package org.moveTrack;
2 |
3 | import android.app.Notification;
4 | import android.app.NotificationChannel;
5 | import android.app.NotificationManager;
6 | import android.app.PendingIntent;
7 | import android.app.Service;
8 | import android.content.BroadcastReceiver;
9 | import android.content.Context;
10 | import android.content.Intent;
11 | import android.content.IntentFilter;
12 | import android.hardware.SensorManager;
13 | import android.net.ConnectivityManager;
14 | import android.net.Network;
15 | import android.net.NetworkCapabilities;
16 | import android.net.NetworkRequest;
17 | import android.os.Binder;
18 | import android.os.Build;
19 | import android.os.Bundle;
20 | import android.os.IBinder;
21 | import android.os.PowerManager;
22 | import android.os.VibrationEffect;
23 | import android.os.Vibrator;
24 |
25 | import androidx.core.app.NotificationCompat;
26 | import androidx.localbroadcastmanager.content.LocalBroadcastManager;
27 |
28 | public class TrackingService extends Service {
29 | private static TrackingService instance = null;
30 | private final IBinder localBinder = new TrackingBinder();
31 | Runnable on_death = () -> {
32 | stopSelf();
33 | LocalBroadcastManager.getInstance(TrackingService.this).sendBroadcast(new Intent("pls-let-me-die"));
34 | };
35 | boolean ignoreWifi = false;
36 | ConnectivityManager.NetworkCallback callback = null;
37 | private UDPGyroProviderClient client;
38 | //private long last_screen_time = 0;
39 | BroadcastReceiver recenterReceiver = new BroadcastReceiver() {
40 | @Override
41 | public void onReceive(Context context, Intent intent) {
42 | if (client != null)
43 | client.button_pushed();
44 | }
45 | };
46 | private GyroListener listener;
47 | private PowerManager.WakeLock wakeLock;
48 | private String ip_address;
49 | private AppStatus stat;
50 | BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
51 | @Override
52 | public void onReceive(Context context, Intent intent) {
53 | if (stat != null) stat.update("Killed.");
54 | if (on_death != null) on_death.run();
55 | }
56 | };
57 |
58 | public static boolean isInstanceCreated() {
59 | return instance != null;
60 | }
61 |
62 | @Override
63 | public void onCreate() {
64 | instance = this;
65 | }
66 |
67 | @Override
68 | public int onStartCommand(Intent intent, int flags, int startId) {
69 | if ((intent == null) || (intent.getExtras() == null)) {
70 | foregroundstuff();
71 | return START_STICKY;
72 | }
73 | Bundle data = intent.getExtras();
74 | ip_address = data.getString("ipAddrTxt");
75 | int port_no = data.getInt("port_no");
76 |
77 | AutoDiscoverer.ConfigSettings cfgSettings = new AutoDiscoverer.ConfigSettings();
78 | cfgSettings.magnetometerEnabled = data.getBoolean("magnetometer");
79 | cfgSettings.madgwickBeta = data.getFloat("madgwickbeta");
80 | cfgSettings.stabilization = data.getBoolean("stabilization");
81 | cfgSettings.sensorData = data.getInt("sensordata");
82 | cfgSettings.smartCorrection = data.getBoolean("smartcorrection");
83 |
84 | System.out.println("Start command");
85 | foregroundstuff();
86 |
87 | stat = new AppStatus((Service) this);
88 | client = new UDPGyroProviderClient(stat, this);
89 | try {
90 | listener = new GyroListener((SensorManager) getSystemService(Context.SENSOR_SERVICE), client, stat, cfgSettings);
91 | } catch (Exception e) {
92 | stat.update("on GyroListener: " + e.toString());
93 | on_death.run();
94 | return START_STICKY;
95 | }
96 |
97 |
98 | try {
99 | Thread thread = new Thread(() -> {
100 | if (!client.setTgt(ip_address, port_no)) {
101 | on_death.run();
102 | } else {
103 | client.connect(on_death);
104 | if (client == null || !client.isConnected()) {
105 | on_death.run();
106 | }
107 | }
108 | });
109 | thread.start();
110 | } catch (OutOfMemoryError err) {
111 | stat.update("Out of memory error when trying to spawn thread");
112 | on_death.run();
113 | return START_STICKY;
114 | }
115 |
116 | listener.register_listeners();
117 |
118 | String tag = "owoTrackVRSync::BackgroundTrackingSync";
119 |
120 | if (Build.VERSION.SDK_INT == Build.VERSION_CODES.M && Build.MANUFACTURER.equals("Huawei")) {
121 | tag = "LocationManagerService";
122 | }
123 |
124 | PowerManager powerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
125 | wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, tag);
126 | wakeLock.acquire();
127 |
128 | register_recenter_yaw();
129 |
130 | ignoreWifi = false;
131 | lockWifi();
132 |
133 | return START_STICKY;
134 | }
135 |
136 | private void lockWifi() {
137 | if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
138 | try {
139 | ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
140 |
141 | if (callback == null) {
142 | callback = new ConnectivityManager.NetworkCallback() {
143 | public void onAvailable(Network network) {
144 | if (ignoreWifi) return;
145 |
146 | super.onAvailable(network);
147 |
148 | try {
149 | connectivityManager.bindProcessToNetwork(network);
150 | } catch (SecurityException ignored) {
151 | }
152 | }
153 | };
154 | }
155 |
156 | connectivityManager.requestNetwork(
157 | new NetworkRequest.Builder().addTransportType(NetworkCapabilities.TRANSPORT_WIFI).build(),
158 | callback
159 | );
160 | } catch (Exception ignored) {
161 | }
162 | }
163 | }
164 |
165 | private void unlockWifi() {
166 | ignoreWifi = true;
167 |
168 | if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
169 |
170 | try {
171 | ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
172 | connectivityManager.bindProcessToNetwork(null);
173 | if (callback != null)
174 | connectivityManager.unregisterNetworkCallback(callback);
175 | callback = null;
176 | } catch (Exception ignored) {
177 | }
178 |
179 | }
180 | }
181 |
182 | @Override
183 | public IBinder onBind(Intent intent) {
184 |
185 | return localBinder;
186 | }
187 |
188 | @Override
189 | public void onRebind(Intent intent) {
190 | super.onRebind(intent);
191 | }
192 |
193 | @Override
194 | public boolean onUnbind(Intent intent) {
195 | return super.onUnbind(intent);
196 | }
197 |
198 | public String getLog() {
199 | if (stat == null) {
200 | return "Service not started";
201 | }
202 | return stat.statusi;
203 | }
204 |
205 | public boolean is_running() {
206 | return stat != null;
207 | }
208 |
209 | @Override
210 | public void onDestroy() {
211 | instance = null;
212 | LocalBroadcastManager.getInstance(this).sendBroadcast(new Intent("cya-ded"));
213 | unlockWifi();
214 | if (listener != null) {
215 | Vibrator v = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
216 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
217 | v.vibrate(VibrationEffect.createOneShot((long) (200), (int) (255)));
218 | } else {
219 | v.vibrate(200);
220 | }
221 | listener.stop();
222 | wakeLock.release();
223 |
224 | unregisterReceiver(broadcastReceiver);
225 | unregisterReceiver(recenterReceiver);
226 |
227 | if (client != null) {
228 | client.stop();
229 | client = null;
230 | }
231 | }
232 |
233 | }
234 |
235 | private void register_recenter_yaw() {
236 | IntentFilter screenStateFilter = new IntentFilter();
237 | screenStateFilter.addAction(Intent.ACTION_SCREEN_ON);
238 | //screenStateFilter.addAction(Intent.ACTION_SCREEN_OFF);
239 | registerReceiver(recenterReceiver, screenStateFilter);
240 | }
241 |
242 | // stupid foreground stuff
243 | private void foregroundstuff() {
244 | NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
245 |
246 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
247 | nm.createNotificationChannel(new NotificationChannel("NOTIFICATION_CHANNEL_ID", "Foreground Service", NotificationManager.IMPORTANCE_DEFAULT));
248 | }
249 |
250 | registerReceiver(broadcastReceiver, new IntentFilter("kill-ze-service"));
251 |
252 | Intent intent = new Intent("kill-ze-service");
253 | PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_IMMUTABLE);
254 |
255 | Notification notification = new NotificationCompat.Builder(this, "NOTIFICATION_CHANNEL_ID")
256 | .setContentTitle("moveTrackVR")
257 | .setTicker("moveTrackVR")
258 | .setContentText("moveTrack service is running")
259 | .setSmallIcon(R.mipmap.ic_launcher)
260 | .addAction(0, "Stop", pendingIntent)
261 | .setOngoing(true).build();
262 |
263 | startForeground(1001, notification);
264 | }
265 |
266 | public class TrackingBinder extends Binder {
267 | public TrackingService getService() {
268 | return TrackingService.this;
269 | }
270 | }
271 | }
272 |
--------------------------------------------------------------------------------
/moveTrackLib/src/main/java/org/moveTrack/math/MadgwickAHRS.java:
--------------------------------------------------------------------------------
1 | package org.moveTrack.math;
2 |
3 |
4 | public class MadgwickAHRS {
5 |
6 | private float samplePeriod;
7 | private float beta;
8 | private float[] quaternion;
9 |
10 | public MadgwickAHRS(float samplePeriod) {
11 | this(samplePeriod, 1f);
12 | }
13 |
14 | public MadgwickAHRS(float samplePeriod, float beta) {
15 | this.samplePeriod = samplePeriod;
16 | this.beta = beta;
17 | this.quaternion = new float[]{1f, 0f, 0f, 0f};
18 | }
19 |
20 | public float getSamplePeriod() {
21 | return samplePeriod;
22 | }
23 |
24 | public void setSamplePeriod(float samplePeriod) {
25 | this.samplePeriod = samplePeriod;
26 | }
27 |
28 | public float getBeta() {
29 | return beta;
30 | }
31 |
32 | public void setBeta(float beta) {
33 | this.beta = beta;
34 | }
35 |
36 | public float[] getQuaternion() {
37 | return quaternion;
38 | }
39 | public void setQuaternion(float w, float x, float y, float z) {
40 | quaternion[0] = w;
41 | quaternion[1] = x;
42 | quaternion[2] = y;
43 | quaternion[3] = z;
44 | }
45 |
46 | public void update(float gx, float gy, float gz, float ax, float ay,
47 | float az, float mx, float my, float mz) {
48 | float q1 = quaternion[0], q2 = quaternion[1], q3 = quaternion[2], q4 = quaternion[3]; // short
49 |
50 | float norm;
51 | float hx, hy, _2bx, _2bz;
52 | float s1, s2, s3, s4;
53 | float qDot1, qDot2, qDot3, qDot4;
54 |
55 | // Auxiliary variables to avoid repeated arithmetic
56 | float _2q1mx;
57 | float _2q1my;
58 | float _2q1mz;
59 | float _2q2mx;
60 | float _4bx;
61 | float _4bz;
62 | float _2q1 = 2f * q1;
63 | float _2q2 = 2f * q2;
64 | float _2q3 = 2f * q3;
65 | float _2q4 = 2f * q4;
66 | float _2q1q3 = 2f * q1 * q3;
67 | float _2q3q4 = 2f * q3 * q4;
68 | float q1q1 = q1 * q1;
69 | float q1q2 = q1 * q2;
70 | float q1q3 = q1 * q3;
71 | float q1q4 = q1 * q4;
72 | float q2q2 = q2 * q2;
73 | float q2q3 = q2 * q3;
74 | float q2q4 = q2 * q4;
75 | float q3q3 = q3 * q3;
76 | float q3q4 = q3 * q4;
77 | float q4q4 = q4 * q4;
78 |
79 | // Normalise accelerometer measurement
80 | norm = (float) Math.sqrt(ax * ax + ay * ay + az * az);
81 | if (norm == 0f)
82 | return; // handle NaN
83 | norm = 1 / norm; // use reciprocal for division
84 | ax *= norm;
85 | ay *= norm;
86 | az *= norm;
87 |
88 | // Normalise magnetometer measurement
89 | norm = (float) Math.sqrt(mx * mx + my * my + mz * mz);
90 | if (norm == 0f)
91 | return; // handle NaN
92 | norm = 1 / norm; // use reciprocal for division
93 | mx *= norm;
94 | my *= norm;
95 | mz *= norm;
96 |
97 | // Reference direction of Earth's magnetic field
98 | _2q1mx = 2f * q1 * mx;
99 | _2q1my = 2f * q1 * my;
100 | _2q1mz = 2f * q1 * mz;
101 | _2q2mx = 2f * q2 * mx;
102 | hx = mx * q1q1 - _2q1my * q4 + _2q1mz * q3 + mx * q2q2 + _2q2 * my * q3
103 | + _2q2 * mz * q4 - mx * q3q3 - mx * q4q4;
104 | hy = _2q1mx * q4 + my * q1q1 - _2q1mz * q2 + _2q2mx * q3 - my * q2q2
105 | + my * q3q3 + _2q3 * mz * q4 - my * q4q4;
106 | _2bx = (float) Math.sqrt(hx * hx + hy * hy);
107 | _2bz = -_2q1mx * q3 + _2q1my * q2 + mz * q1q1 + _2q2mx * q4 - mz * q2q2
108 | + _2q3 * my * q4 - mz * q3q3 + mz * q4q4;
109 | _4bx = 2f * _2bx;
110 | _4bz = 2f * _2bz;
111 |
112 | // Gradient decent algorithm corrective step
113 | s1 = -_2q3 * (2f * q2q4 - _2q1q3 - ax) + _2q2
114 | * (2f * q1q2 + _2q3q4 - ay) - _2bz * q3
115 | * (_2bx * (0.5f - q3q3 - q4q4) + _2bz * (q2q4 - q1q3) - mx)
116 | + (-_2bx * q4 + _2bz * q2)
117 | * (_2bx * (q2q3 - q1q4) + _2bz * (q1q2 + q3q4) - my) + _2bx
118 | * q3
119 | * (_2bx * (q1q3 + q2q4) + _2bz * (0.5f - q2q2 - q3q3) - mz);
120 | s2 = _2q4 * (2f * q2q4 - _2q1q3 - ax) + _2q1
121 | * (2f * q1q2 + _2q3q4 - ay) - 4f * q2
122 | * (1 - 2f * q2q2 - 2f * q3q3 - az) + _2bz * q4
123 | * (_2bx * (0.5f - q3q3 - q4q4) + _2bz * (q2q4 - q1q3) - mx)
124 | + (_2bx * q3 + _2bz * q1)
125 | * (_2bx * (q2q3 - q1q4) + _2bz * (q1q2 + q3q4) - my)
126 | + (_2bx * q4 - _4bz * q2)
127 | * (_2bx * (q1q3 + q2q4) + _2bz * (0.5f - q2q2 - q3q3) - mz);
128 | s3 = -_2q1 * (2f * q2q4 - _2q1q3 - ax) + _2q4
129 | * (2f * q1q2 + _2q3q4 - ay) - 4f * q3
130 | * (1 - 2f * q2q2 - 2f * q3q3 - az) + (-_4bx * q3 - _2bz * q1)
131 | * (_2bx * (0.5f - q3q3 - q4q4) + _2bz * (q2q4 - q1q3) - mx)
132 | + (_2bx * q2 + _2bz * q4)
133 | * (_2bx * (q2q3 - q1q4) + _2bz * (q1q2 + q3q4) - my)
134 | + (_2bx * q1 - _4bz * q3)
135 | * (_2bx * (q1q3 + q2q4) + _2bz * (0.5f - q2q2 - q3q3) - mz);
136 | s4 = _2q2 * (2f * q2q4 - _2q1q3 - ax) + _2q3
137 | * (2f * q1q2 + _2q3q4 - ay) + (-_4bx * q4 + _2bz * q2)
138 | * (_2bx * (0.5f - q3q3 - q4q4) + _2bz * (q2q4 - q1q3) - mx)
139 | + (-_2bx * q1 + _2bz * q3)
140 | * (_2bx * (q2q3 - q1q4) + _2bz * (q1q2 + q3q4) - my) + _2bx
141 | * q2
142 | * (_2bx * (q1q3 + q2q4) + _2bz * (0.5f - q2q2 - q3q3) - mz);
143 | norm = 1f / (float) Math.sqrt(s1 * s1 + s2 * s2 + s3 * s3 + s4 * s4); // normalise
144 | // step
145 | // magnitude
146 | s1 *= norm;
147 | s2 *= norm;
148 | s3 *= norm;
149 | s4 *= norm;
150 |
151 | // Compute rate of change of quaternion
152 | qDot1 = 0.5f * (-q2 * gx - q3 * gy - q4 * gz) - beta * s1;
153 | qDot2 = 0.5f * (q1 * gx + q3 * gz - q4 * gy) - beta * s2;
154 | qDot3 = 0.5f * (q1 * gy - q2 * gz + q4 * gx) - beta * s3;
155 | qDot4 = 0.5f * (q1 * gz + q2 * gy - q3 * gx) - beta * s4;
156 |
157 | // Integrate to yield quaternion
158 | q1 += qDot1 * samplePeriod;
159 | q2 += qDot2 * samplePeriod;
160 | q3 += qDot3 * samplePeriod;
161 | q4 += qDot4 * samplePeriod;
162 | norm = 1f / (float) Math.sqrt(q1 * q1 + q2 * q2 + q3 * q3 + q4 * q4); // normalise
163 | // quaternion
164 | quaternion[0] = q1 * norm;
165 | quaternion[1] = q2 * norm;
166 | quaternion[2] = q3 * norm;
167 | quaternion[3] = q4 * norm;
168 | }
169 |
170 | public void update(float gx, float gy, float gz, float ax, float ay,
171 | float az) {
172 | float q1 = quaternion[0], q2 = quaternion[1], q3 = quaternion[2], q4 = quaternion[3]; // short
173 | // name
174 | // local
175 | // variable
176 | // for
177 | // readability
178 | float norm;
179 | float s1, s2, s3, s4;
180 | float qDot1, qDot2, qDot3, qDot4;
181 |
182 | // Auxiliary variables to avoid repeated arithmetic
183 | float _2q1 = 2f * q1;
184 | float _2q2 = 2f * q2;
185 | float _2q3 = 2f * q3;
186 | float _2q4 = 2f * q4;
187 | float _4q1 = 4f * q1;
188 | float _4q2 = 4f * q2;
189 | float _4q3 = 4f * q3;
190 | float _8q2 = 8f * q2;
191 | float _8q3 = 8f * q3;
192 | float q1q1 = q1 * q1;
193 | float q2q2 = q2 * q2;
194 | float q3q3 = q3 * q3;
195 | float q4q4 = q4 * q4;
196 |
197 | // Normalise accelerometer measurement
198 | norm = (float) Math.sqrt(ax * ax + ay * ay + az * az);
199 | if (norm == 0f)
200 | return; // handle NaN
201 | norm = 1 / norm; // use reciprocal for division
202 | ax *= norm;
203 | ay *= norm;
204 | az *= norm;
205 |
206 | // Gradient decent algorithm corrective step
207 | s1 = _4q1 * q3q3 + _2q3 * ax + _4q1 * q2q2 - _2q2 * ay;
208 | s2 = _4q2 * q4q4 - _2q4 * ax + 4f * q1q1 * q2 - _2q1 * ay - _4q2 + _8q2
209 | * q2q2 + _8q2 * q3q3 + _4q2 * az;
210 | s3 = 4f * q1q1 * q3 + _2q1 * ax + _4q3 * q4q4 - _2q4 * ay - _4q3 + _8q3
211 | * q2q2 + _8q3 * q3q3 + _4q3 * az;
212 | s4 = 4f * q2q2 * q4 - _2q2 * ax + 4f * q3q3 * q4 - _2q3 * ay;
213 | norm = 1f / (float) Math.sqrt(s1 * s1 + s2 * s2 + s3 * s3 + s4 * s4); // normalise
214 | // step
215 | // magnitude
216 | s1 *= norm;
217 | s2 *= norm;
218 | s3 *= norm;
219 | s4 *= norm;
220 |
221 | // Compute rate of change of quaternion
222 | qDot1 = 0.5f * (-q2 * gx - q3 * gy - q4 * gz) - beta * s1;
223 | qDot2 = 0.5f * (q1 * gx + q3 * gz - q4 * gy) - beta * s2;
224 | qDot3 = 0.5f * (q1 * gy - q2 * gz + q4 * gx) - beta * s3;
225 | qDot4 = 0.5f * (q1 * gz + q2 * gy - q3 * gx) - beta * s4;
226 |
227 | // Integrate to yield quaternion
228 | q1 += qDot1 * samplePeriod;
229 | q2 += qDot2 * samplePeriod;
230 | q3 += qDot3 * samplePeriod;
231 | q4 += qDot4 * samplePeriod;
232 | norm = 1f / (float) Math.sqrt(q1 * q1 + q2 * q2 + q3 * q3 + q4 * q4); // normalise
233 | // quaternion
234 | quaternion[0] = q1 * norm;
235 | quaternion[1] = q2 * norm;
236 | quaternion[2] = q3 * norm;
237 | quaternion[3] = q4 * norm;
238 | }
239 |
240 | }
--------------------------------------------------------------------------------
/moveTrackLib/src/main/java/org/moveTrack/math/Quaternion.java:
--------------------------------------------------------------------------------
1 | package org.moveTrack.math;
2 |
3 |
4 | import static java.lang.Math.cos;
5 | import static java.lang.Math.sin;
6 |
7 | /**
8 | * Quaternions are data structures built from unicorn horns.
9 | *
10 | * I nabbed this implementation from The Internet.
11 | */
12 | public final class Quaternion {
13 | private double x;
14 | private double y;
15 | private double z;
16 | private double w;
17 | //private float[] matrixs;
18 |
19 | public Quaternion(final Quaternion q) {
20 | this(q.x, q.y, q.z, q.w);
21 | }
22 |
23 | public Quaternion(double x, double y, double z, double w) {
24 | this.x = x;
25 | this.y = y;
26 | this.z = z;
27 | this.w = w;
28 | }
29 |
30 | public Quaternion(Vector3 axis, double angle) {
31 | set(axis, angle);
32 | }
33 |
34 | public static Quaternion create_from_axis_angle(float xx, float yy, float zz, float a) {
35 | // Here we calculate the sin( theta / 2) once for optimization
36 | float factor = (float) sin(a / 2.0);
37 |
38 | // Calculate the x, y and z of the quaternion
39 | float x = xx * factor;
40 | float y = yy * factor;
41 | float z = zz * factor;
42 |
43 | // Calcualte the w value by cos( theta / 2 )
44 | float w = (float) cos(a / 2.0);
45 |
46 | Quaternion quat = new Quaternion(x, y, z, w);
47 | quat.normalizeThis();
48 | return quat;
49 | }
50 |
51 | public void set(final Quaternion q) {
52 | //matrixs = null;
53 | this.x = q.x;
54 | this.y = q.y;
55 | this.z = q.z;
56 | this.w = q.w;
57 | }
58 |
59 | public double norm() {
60 | return Math.sqrt(dot(this));
61 | }
62 |
63 | public double getW() {
64 | return w;
65 | }
66 |
67 | public double getX() {
68 | return x;
69 | }
70 |
71 | public double getY() {
72 | return y;
73 | }
74 |
75 | public double getZ() {
76 | return z;
77 | }
78 |
79 | /**
80 | * @param axis rotation axis, unit vector
81 | * @param angle the rotation angle
82 | * @return this
83 | */
84 | public Quaternion set(Vector3 axis, double angle) {
85 | //matrixs = null;
86 | double s = (double) sin(angle / 2);
87 | w = (double) cos(angle / 2);
88 | x = axis.getX() * s;
89 | y = axis.getY() * s;
90 | z = axis.getZ() * s;
91 | return this;
92 | }
93 |
94 | public Quaternion mulThis(Quaternion q) {
95 | //matrixs = null;
96 | double nw = w * q.w - x * q.x - y * q.y - z * q.z;
97 | double nx = w * q.x + x * q.w + y * q.z - z * q.y;
98 | double ny = w * q.y + y * q.w + z * q.x - x * q.z;
99 | z = w * q.z + z * q.w + x * q.y - y * q.x;
100 | w = nw;
101 | x = nx;
102 | y = ny;
103 | return this;
104 | }
105 |
106 | public Quaternion scaleThis(double scale) {
107 | if (scale != 1) {
108 | //matrixs = null;
109 | w *= scale;
110 | x *= scale;
111 | y *= scale;
112 | z *= scale;
113 | }
114 | return this;
115 | }
116 |
117 | public Quaternion divThis(double scale) {
118 | if (scale != 1) {
119 | //matrixs = null;
120 | w /= scale;
121 | x /= scale;
122 | y /= scale;
123 | z /= scale;
124 | }
125 | return this;
126 | }
127 |
128 | public double dot(Quaternion q) {
129 | return x * q.x + y * q.y + z * q.z + w * q.w;
130 | }
131 |
132 | public boolean equals(Quaternion q) {
133 | return x == q.x && y == q.y && z == q.z && w == q.w;
134 | }
135 |
136 | public Quaternion interpolateThis(Quaternion q, double t) {
137 | if (!equals(q)) {
138 | double d = dot(q);
139 | double qx, qy, qz, qw;
140 |
141 | if (d < 0f) {
142 | qx = -q.x;
143 | qy = -q.y;
144 | qz = -q.z;
145 | qw = -q.w;
146 | d = -d;
147 | } else {
148 | qx = q.x;
149 | qy = q.y;
150 | qz = q.z;
151 | qw = q.w;
152 | }
153 |
154 | double f0, f1;
155 |
156 | if ((1 - d) > 0.1f) {
157 | double angle = (double) Math.acos(d);
158 | double s = (double) sin(angle);
159 | double tAngle = t * angle;
160 | f0 = (double) sin(angle - tAngle) / s;
161 | f1 = (double) sin(tAngle) / s;
162 | } else {
163 | f0 = 1 - t;
164 | f1 = t;
165 | }
166 |
167 | x = f0 * x + f1 * qx;
168 | y = f0 * y + f1 * qy;
169 | z = f0 * z + f1 * qz;
170 | w = f0 * w + f1 * qw;
171 | }
172 |
173 | return this;
174 | }
175 |
176 | public Quaternion normalizeThis() {
177 | return divThis(norm());
178 | }
179 |
180 | public Quaternion interpolate(Quaternion q, double t) {
181 | return new Quaternion(this).interpolateThis(q, t);
182 | }
183 |
184 | /**
185 | * Converts this Quaternion into a matrix, returning it as a float array.
186 | */
187 | public float[] toMatrix() {
188 | float[] matrixs = new float[16];
189 | toMatrix(matrixs);
190 | return matrixs;
191 | }
192 |
193 | /**
194 | * Converts this Quaternion into a matrix, placing the values into the given array.
195 | *
196 | * @param matrixs 16-length float array.
197 | */
198 | public final void toMatrix(float[] matrixs) {
199 | matrixs[3] = 0.0f;
200 | matrixs[7] = 0.0f;
201 | matrixs[11] = 0.0f;
202 | matrixs[12] = 0.0f;
203 | matrixs[13] = 0.0f;
204 | matrixs[14] = 0.0f;
205 | matrixs[15] = 1.0f;
206 |
207 | matrixs[0] = (float) (1.0f - (2.0f * ((y * y) + (z * z))));
208 | matrixs[1] = (float) (2.0f * ((x * y) - (z * w)));
209 | matrixs[2] = (float) (2.0f * ((x * z) + (y * w)));
210 |
211 | matrixs[4] = (float) (2.0f * ((x * y) + (z * w)));
212 | matrixs[5] = (float) (1.0f - (2.0f * ((x * x) + (z * z))));
213 | matrixs[6] = (float) (2.0f * ((y * z) - (x * w)));
214 |
215 | matrixs[8] = (float) (2.0f * ((x * z) - (y * w)));
216 | matrixs[9] = (float) (2.0f * ((y * z) + (x * w)));
217 | matrixs[10] = (float) (1.0f - (2.0f * ((x * x) + (y * y))));
218 | }
219 |
220 | public float yaw() {
221 | return (float) Math.atan2(2.0f * (w * z + x * y), w * w + x * x - y * y - z * z);
222 | }
223 | }
--------------------------------------------------------------------------------
/moveTrackLib/src/main/java/org/moveTrack/math/Vector3.java:
--------------------------------------------------------------------------------
1 | package org.moveTrack.math;
2 |
3 | public final class Vector3 {
4 | private double x, y, z;
5 |
6 | public Vector3(double ix, double iy, double iz) {
7 | x = ix;
8 | y = iy;
9 | z = iz;
10 | }
11 |
12 | public double getX() {
13 | return x;
14 | }
15 |
16 | public double getY() {
17 | return y;
18 | }
19 |
20 | public double getZ() {
21 | return z;
22 | }
23 |
24 | public void set(double ix, double iy, double iz) {
25 | x = ix;
26 | y = iy;
27 | z = iz;
28 | }
29 |
30 | public double magnitude() {
31 | return Math.sqrt(x * x + y * y + z * z);
32 | }
33 |
34 | public void multiply(double f) {
35 | x *= f;
36 | y *= f;
37 | z *= f;
38 | }
39 |
40 | public void normalise() {
41 | double mag = magnitude();
42 | x /= mag;
43 | y /= mag;
44 | z /= mag;
45 | }
46 | }
--------------------------------------------------------------------------------
/moveTrackLib/src/main/res/drawable/empty_tall_divider.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
--------------------------------------------------------------------------------
/moveTrackLib/src/main/res/drawable/error_missing.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/moveTrackLib/src/main/res/drawable/ic_baseline_computer_24.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/moveTrackLib/src/main/res/drawable/ic_baseline_help_outline_24.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/moveTrackLib/src/main/res/drawable/ic_baseline_home_24.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/moveTrackLib/src/main/res/drawable/not_missing.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/moveTrackLib/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/moveTrackLib/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/moveTrackLib/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Timocop/moveTrackVR/c99ab44c9fe1e34622bc63070909e88d7103eb2d/moveTrackLib/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/moveTrackLib/src/main/res/mipmap-hdpi/ic_launcher_background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Timocop/moveTrackVR/c99ab44c9fe1e34622bc63070909e88d7103eb2d/moveTrackLib/src/main/res/mipmap-hdpi/ic_launcher_background.png
--------------------------------------------------------------------------------
/moveTrackLib/src/main/res/mipmap-hdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Timocop/moveTrackVR/c99ab44c9fe1e34622bc63070909e88d7103eb2d/moveTrackLib/src/main/res/mipmap-hdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/moveTrackLib/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Timocop/moveTrackVR/c99ab44c9fe1e34622bc63070909e88d7103eb2d/moveTrackLib/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/moveTrackLib/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Timocop/moveTrackVR/c99ab44c9fe1e34622bc63070909e88d7103eb2d/moveTrackLib/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/moveTrackLib/src/main/res/mipmap-mdpi/ic_launcher_background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Timocop/moveTrackVR/c99ab44c9fe1e34622bc63070909e88d7103eb2d/moveTrackLib/src/main/res/mipmap-mdpi/ic_launcher_background.png
--------------------------------------------------------------------------------
/moveTrackLib/src/main/res/mipmap-mdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Timocop/moveTrackVR/c99ab44c9fe1e34622bc63070909e88d7103eb2d/moveTrackLib/src/main/res/mipmap-mdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/moveTrackLib/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Timocop/moveTrackVR/c99ab44c9fe1e34622bc63070909e88d7103eb2d/moveTrackLib/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/moveTrackLib/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Timocop/moveTrackVR/c99ab44c9fe1e34622bc63070909e88d7103eb2d/moveTrackLib/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/moveTrackLib/src/main/res/mipmap-xhdpi/ic_launcher_background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Timocop/moveTrackVR/c99ab44c9fe1e34622bc63070909e88d7103eb2d/moveTrackLib/src/main/res/mipmap-xhdpi/ic_launcher_background.png
--------------------------------------------------------------------------------
/moveTrackLib/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Timocop/moveTrackVR/c99ab44c9fe1e34622bc63070909e88d7103eb2d/moveTrackLib/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/moveTrackLib/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Timocop/moveTrackVR/c99ab44c9fe1e34622bc63070909e88d7103eb2d/moveTrackLib/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/moveTrackLib/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Timocop/moveTrackVR/c99ab44c9fe1e34622bc63070909e88d7103eb2d/moveTrackLib/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/moveTrackLib/src/main/res/mipmap-xxhdpi/ic_launcher_background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Timocop/moveTrackVR/c99ab44c9fe1e34622bc63070909e88d7103eb2d/moveTrackLib/src/main/res/mipmap-xxhdpi/ic_launcher_background.png
--------------------------------------------------------------------------------
/moveTrackLib/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Timocop/moveTrackVR/c99ab44c9fe1e34622bc63070909e88d7103eb2d/moveTrackLib/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/moveTrackLib/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Timocop/moveTrackVR/c99ab44c9fe1e34622bc63070909e88d7103eb2d/moveTrackLib/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/moveTrackLib/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Timocop/moveTrackVR/c99ab44c9fe1e34622bc63070909e88d7103eb2d/moveTrackLib/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/moveTrackLib/src/main/res/mipmap-xxxhdpi/ic_launcher_background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Timocop/moveTrackVR/c99ab44c9fe1e34622bc63070909e88d7103eb2d/moveTrackLib/src/main/res/mipmap-xxxhdpi/ic_launcher_background.png
--------------------------------------------------------------------------------
/moveTrackLib/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Timocop/moveTrackVR/c99ab44c9fe1e34622bc63070909e88d7103eb2d/moveTrackLib/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/moveTrackLib/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Timocop/moveTrackVR/c99ab44c9fe1e34622bc63070909e88d7103eb2d/moveTrackLib/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/moveTrackLib/src/main/res/values-night/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
16 |
--------------------------------------------------------------------------------
/moveTrackLib/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #F80000
4 | #255
5 | #18EEFF
6 | #1BB3FF
7 | #2ADAFF
8 | #017784
9 | #FF000000
10 | #FFFFFFFF
11 |
--------------------------------------------------------------------------------
/moveTrackMobile/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/moveTrackMobile/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'com.android.application'
3 | }
4 |
5 | android {
6 | compileSdkVersion 31
7 |
8 | defaultConfig {
9 | applicationId 'org.movevrtrackersync'
10 | minSdkVersion 16
11 | targetSdkVersion 31
12 | versionCode 19
13 | versionName '9.7.9'
14 |
15 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
16 | }
17 |
18 | buildTypes {
19 | release {
20 | minifyEnabled false
21 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
22 | }
23 | }
24 | compileOptions {
25 | sourceCompatibility JavaVersion.VERSION_1_8
26 | targetCompatibility JavaVersion.VERSION_1_8
27 | }
28 | }
29 |
30 | dependencies {
31 |
32 | implementation 'androidx.appcompat:appcompat:1.1.0'
33 | implementation 'com.google.android.material:material:1.1.0'
34 | implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
35 | implementation 'androidx.legacy:legacy-support-v4:1.0.0'
36 |
37 | def nav_version = "2.3.1"
38 |
39 | // Java language implementation
40 | implementation "androidx.navigation:navigation-fragment:$nav_version"
41 | implementation "androidx.navigation:navigation-ui:$nav_version"
42 |
43 | // Feature module Support
44 | implementation "androidx.navigation:navigation-dynamic-features-fragment:$nav_version"
45 |
46 | implementation 'androidx.localbroadcastmanager:localbroadcastmanager:1.0.0'
47 | implementation project(':moveTrackLib')
48 |
49 |
50 | }
--------------------------------------------------------------------------------
/moveTrackMobile/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
--------------------------------------------------------------------------------
/moveTrackMobile/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
20 |
23 |
24 |
25 |
26 |
27 |
28 |
33 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/moveTrackMobile/src/main/java/org/moveTrack/Mobile/MainActivity.java:
--------------------------------------------------------------------------------
1 | package org.moveTrack.Mobile;
2 |
3 |
4 | import android.content.Context;
5 | import android.content.SharedPreferences;
6 | import android.hardware.Sensor;
7 | import android.hardware.SensorManager;
8 | import android.os.Bundle;
9 |
10 | import androidx.appcompat.app.AppCompatActivity;
11 | import androidx.navigation.NavController;
12 | import androidx.navigation.Navigation;
13 | import androidx.navigation.ui.NavigationUI;
14 |
15 | import com.google.android.material.bottomnavigation.BottomNavigationView;
16 |
17 | import org.moveTrack.AutoDiscoverer;
18 | import org.moveTrack.Handshaker;
19 | import org.moveTrack.Mobile.ui.ConnectFragment;
20 |
21 | public class MainActivity extends AppCompatActivity {
22 |
23 | public static boolean[] sensor_exist;
24 | public static NavController contr;
25 | private static String missingSensorMessage = "";
26 |
27 | public static boolean getSensorExists(int sensor) {
28 | if ((sensor < 0) || (sensor >= 3)) return false;
29 | return sensor_exist[sensor];
30 | }
31 |
32 | public static boolean hasAnySensorsAtAll() {
33 | return getSensorExists(0) || getSensorExists(1);
34 | }
35 |
36 | public static String getSensorText() {
37 | return missingSensorMessage;
38 | }
39 |
40 | private void fillSensorArray() {
41 | SensorManager man = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
42 |
43 | sensor_exist = new boolean[3];
44 |
45 | sensor_exist[0] = (
46 | man.getDefaultSensor(Sensor.TYPE_GYROSCOPE) != null ||
47 | man.getDefaultSensor(Sensor.TYPE_GYROSCOPE_UNCALIBRATED) != null
48 | );
49 | sensor_exist[1] = (
50 | man.getDefaultSensor(Sensor.TYPE_ACCELEROMETER) != null ||
51 | man.getDefaultSensor(Sensor.TYPE_ACCELEROMETER_UNCALIBRATED) != null
52 | );
53 | sensor_exist[2] = man.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD) != null;
54 |
55 | missingSensorMessage = "";
56 |
57 | if (!hasAnySensorsAtAll()) {
58 | missingSensorMessage = getString(R.string.sensors_missing_all);
59 | }
60 |
61 | }
62 |
63 | private void ensureUUIDSet() {
64 | SharedPreferences prefs = getSharedPreferences("FakeMAC", Context.MODE_PRIVATE);
65 |
66 | long val = -1;
67 | if (!prefs.contains("FakeMACValue")) {
68 | SharedPreferences.Editor editor = prefs.edit();
69 | val = (new java.util.Random()).nextLong();
70 | editor.putLong("FakeMACValue", val);
71 | editor.apply();
72 | } else {
73 | val = prefs.getLong("FakeMACValue", 1);
74 | }
75 |
76 | Handshaker.setMac(val);
77 | }
78 |
79 | private AutoDiscoverer.ConfigSettings connect(String ip, int port) {
80 | SharedPreferences prefs = ConnectFragment.get_prefs(this);
81 | SharedPreferences.Editor editor = prefs.edit();
82 |
83 | editor.putString("ip_address", ip);
84 | editor.putInt("port", port);
85 |
86 | editor.apply();
87 |
88 |
89 | contr.navigate(R.id.connectFragment);
90 |
91 | AutoDiscoverer.ConfigSettings configSettings = new AutoDiscoverer.ConfigSettings();
92 | configSettings.magnetometerEnabled = prefs.getBoolean("magnetometer", true);
93 | configSettings.madgwickBeta = prefs.getFloat("madgwickbeta", 0.1f);
94 | configSettings.stabilization = prefs.getBoolean("stabilization", false);
95 | configSettings.sensorData = prefs.getInt("sensordata", 0);
96 | configSettings.smartCorrection = prefs.getBoolean("smartcorrection", true);
97 | return configSettings;
98 | }
99 |
100 | private void runDiscovery() {
101 | if (!hasAnySensorsAtAll()) return;
102 | if (!AutoDiscoverer.discoveryStillNecessary) return;
103 |
104 | try {
105 | AutoDiscoverer disc = new AutoDiscoverer(this, this::connect);
106 | Thread thrd = new Thread(disc::try_discover);
107 | thrd.start();
108 | } catch (OutOfMemoryError ignored) {
109 | }
110 | }
111 |
112 | @Override
113 | protected void onCreate(Bundle savedInstanceState) {
114 | super.onCreate(savedInstanceState);
115 |
116 | ensureUUIDSet();
117 | fillSensorArray();
118 |
119 | setContentView(R.layout.activity_main);
120 |
121 | contr = Navigation.findNavController(this, R.id.fragment);
122 |
123 | BottomNavigationView nav = findViewById(R.id.nav_view);
124 |
125 | NavigationUI.setupWithNavController(nav, contr);
126 |
127 | runDiscovery();
128 | }
129 |
130 | @Override
131 | protected void onDestroy() {
132 | super.onDestroy();
133 | }
134 |
135 | @Override
136 | protected void onPause() {
137 | super.onPause();
138 | }
139 |
140 | @Override
141 | protected void onResume() {
142 | super.onResume();
143 | }
144 | }
--------------------------------------------------------------------------------
/moveTrackMobile/src/main/java/org/moveTrack/Mobile/ui/ConnectFragment.java:
--------------------------------------------------------------------------------
1 | package org.moveTrack.Mobile.ui;
2 |
3 | import android.content.Context;
4 | import android.content.Intent;
5 | import android.content.SharedPreferences;
6 | import android.os.Build;
7 | import android.os.Bundle;
8 | import android.view.LayoutInflater;
9 | import android.view.View;
10 | import android.view.ViewGroup;
11 | import android.widget.Button;
12 | import android.widget.EditText;
13 | import android.widget.RadioButton;
14 | import android.widget.SeekBar;
15 | import android.widget.Switch;
16 | import android.widget.TextView;
17 |
18 | import androidx.fragment.app.Fragment;
19 |
20 | import org.moveTrack.Mobile.MainActivity;
21 | import org.moveTrack.Mobile.R;
22 | import org.moveTrack.TrackingService;
23 |
24 | /**
25 | * A simple {@link Fragment} subclass.
26 | * Use the {@link ConnectFragment#newInstance} factory method to
27 | * create an instance of this fragment.
28 | */
29 | public class ConnectFragment extends GenericBindingFragment {
30 |
31 | final static String CONN_DATA = "CONNECTION_DATA_PREF";
32 | Button connect_button = null;
33 | EditText ipAddrTxt = null;
34 | EditText portTxt = null;
35 | Switch magBox = null;
36 | SeekBar madgwickBetaBox = null;
37 | Switch stabilizationBox = null;
38 | RadioButton sensorDataDisabled = null;
39 | RadioButton sensorDataCompat = null;
40 | RadioButton sensorDataAll = null;
41 | Switch smartCorrection = null;
42 | SharedPreferences.OnSharedPreferenceChangeListener listener = new SharedPreferences.OnSharedPreferenceChangeListener() {
43 | @Override
44 | public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, java.lang.String s) {
45 | if (s.equals("ip_address")) {
46 | ipAddrTxt.setText(sharedPreferences.getString(s, ""));
47 | }
48 | if (s.equals("port")) {
49 | portTxt.setText(String.valueOf(sharedPreferences.getInt(s, 6969)));
50 | }
51 | }
52 | };
53 | public ConnectFragment() {
54 | }
55 |
56 | public static SharedPreferences get_prefs(Context c) {
57 | return c.getSharedPreferences(CONN_DATA, Context.MODE_PRIVATE);
58 | }
59 |
60 | public static ConnectFragment newInstance() {
61 | ConnectFragment fragment = new ConnectFragment();
62 | Bundle args = new Bundle();
63 | fragment.setArguments(args);
64 | return fragment;
65 | }
66 |
67 | public SharedPreferences get_prefs() {
68 | return get_prefs(getContext());
69 | }
70 |
71 | @Override
72 | protected void onSetStatus(String to) {
73 | if (curr_view == null) return;
74 |
75 | TextView text = curr_view.findViewById(R.id.statusText);
76 |
77 | if (text != null)
78 | text.setText(to.split("\n")[0]);
79 | }
80 |
81 | @Override
82 | protected void onConnectionStatus(boolean to) {
83 | if (connect_button != null)
84 | connect_button.setText(to ? "Disconnect" : "Connect");
85 |
86 | if (ipAddrTxt != null)
87 | ipAddrTxt.setEnabled(!to);
88 |
89 | if (portTxt != null)
90 | portTxt.setEnabled(!to);
91 |
92 | if (magBox != null)
93 | magBox.setEnabled(!to);
94 |
95 | if (madgwickBetaBox != null)
96 | madgwickBetaBox.setEnabled(!to);
97 |
98 | if (stabilizationBox != null)
99 | stabilizationBox.setEnabled(!to);
100 |
101 | if (sensorDataDisabled != null)
102 | sensorDataDisabled.setEnabled(!to);
103 |
104 | if (sensorDataCompat != null)
105 | sensorDataCompat.setEnabled(!to);
106 |
107 | if (sensorDataAll != null)
108 | sensorDataAll.setEnabled(!to);
109 |
110 | if (smartCorrection != null)
111 | smartCorrection.setEnabled(!to);
112 | }
113 |
114 | @Override
115 | public void onDestroy() {
116 | get_prefs().unregisterOnSharedPreferenceChangeListener(listener);
117 | save_data();
118 |
119 | super.onDestroy();
120 | }
121 |
122 | @Override
123 | public View onCreateView(LayoutInflater inflater, ViewGroup container,
124 | Bundle savedInstanceState) {
125 | curr_view = inflater.inflate(R.layout.fragment_connect, container, false);
126 |
127 | connect_button = curr_view.findViewById(R.id.connectButton);
128 | ipAddrTxt = curr_view.findViewById(R.id.editIP);
129 | portTxt = curr_view.findViewById(R.id.editPort);
130 | magBox = curr_view.findViewById(R.id.editMagnetometer);
131 | madgwickBetaBox = curr_view.findViewById(R.id.seekMadgwickBeta);
132 | stabilizationBox = curr_view.findViewById(R.id.editStabilization);
133 | sensorDataDisabled = curr_view.findViewById(R.id.radioSensordata0);
134 | sensorDataCompat = curr_view.findViewById(R.id.radioSensordata1);
135 | sensorDataAll = curr_view.findViewById(R.id.radioSensordata2);
136 | smartCorrection = curr_view.findViewById(R.id.editSmartCorrection);
137 |
138 |
139 | if (!MainActivity.hasAnySensorsAtAll()) {
140 | connect_button.setEnabled(false);
141 | ipAddrTxt.setEnabled(false);
142 | portTxt.setEnabled(false);
143 | magBox.setEnabled(false);
144 | madgwickBetaBox.setEnabled(false);
145 | stabilizationBox.setEnabled(false);
146 | sensorDataDisabled.setEnabled(false);
147 | sensorDataCompat.setEnabled(false);
148 | sensorDataAll.setEnabled(false);
149 | smartCorrection.setEnabled(false);
150 |
151 | TextView statusText = curr_view.findViewById(R.id.statusText);
152 | statusText.setText(R.string.sensors_missing_all);
153 | } else {
154 | SharedPreferences prefs = get_prefs();
155 |
156 | ipAddrTxt.setText(prefs.getString("ip_address", ""));
157 | portTxt.setText(String.valueOf(prefs.getInt("port", 6969)));
158 | magBox.setChecked(prefs.getBoolean("magnetometer", true));
159 | madgwickBetaBox.setProgress((int) (prefs.getFloat("madgwickbeta", 0.1f) * 10.f));
160 | stabilizationBox.setChecked(prefs.getBoolean("stabilization", false));
161 | switch(prefs.getInt("sensordata", 0)) {
162 | case 0:
163 | sensorDataDisabled.setChecked(true);
164 | sensorDataCompat.setChecked(false);
165 | sensorDataAll.setChecked(false);
166 | break;
167 | case 1:
168 | sensorDataDisabled.setChecked(false);
169 | sensorDataCompat.setChecked(true);
170 | sensorDataAll.setChecked(false);
171 | break;
172 | case 2:
173 | sensorDataDisabled.setChecked(false);
174 | sensorDataCompat.setChecked(false);
175 | sensorDataAll.setChecked(true);
176 | break;
177 | }
178 | smartCorrection.setChecked(prefs.getBoolean("smartcorrection", true));
179 |
180 | connect_button.setOnClickListener(v -> onConnect(false));
181 |
182 | prefs.registerOnSharedPreferenceChangeListener(listener);
183 |
184 | onConnectionStatus(TrackingService.isInstanceCreated());
185 | }
186 |
187 | return curr_view;
188 | }
189 |
190 | private String get_ip_address() {
191 | String filtered_ip = String.valueOf(ipAddrTxt.getText()).replaceAll("[^0-9\\.]", "");
192 | ipAddrTxt.setText(filtered_ip);
193 |
194 | return filtered_ip;
195 | }
196 |
197 | private int get_port() {
198 | String filtered_port = String.valueOf(portTxt.getText()).replaceAll("[^0-9]", "");
199 | portTxt.setText(filtered_port);
200 |
201 | int val = 6969;
202 | try {
203 | val = Integer.parseInt(filtered_port);
204 | } catch (NumberFormatException ignored) {
205 | }
206 |
207 | return val;
208 | }
209 |
210 | private boolean get_mag() {
211 | return magBox.isChecked();
212 | }
213 |
214 | private float get_madgwickbeta() {
215 | return (madgwickBetaBox.getProgress() / 10.f);
216 | }
217 |
218 | private boolean get_stabilization() {
219 | return stabilizationBox.isChecked();
220 | }
221 |
222 | private int get_sensordata() {
223 | if(sensorDataDisabled.isChecked())
224 | return 0;
225 | if(sensorDataCompat.isChecked())
226 | return 1;
227 | if(sensorDataAll.isChecked())
228 | return 2;
229 |
230 | return 0;
231 | }
232 | private boolean get_smartconnection() { return smartCorrection.isChecked(); }
233 |
234 | private void onConnect(boolean auto) {
235 | if ((service_v != null) && (service_v.is_running())) {
236 | onSetStatus("Killing service...");
237 | Intent intent = new Intent("kill-ze-service");
238 | getContext().sendBroadcast(intent);
239 | return;
240 | }
241 |
242 |
243 | onConnectionStatus(true);
244 |
245 | Intent mainIntent = new Intent(getContext(), TrackingService.class);
246 | if (auto) {
247 | mainIntent.putExtra("ipAddrTxt", "255.255.255.255");
248 | } else {
249 | mainIntent.putExtra("ipAddrTxt", get_ip_address());
250 | }
251 |
252 | mainIntent.putExtra("port_no", get_port());
253 | mainIntent.putExtra("magnetometer", get_mag());
254 | mainIntent.putExtra("madgwickbeta", get_madgwickbeta());
255 | mainIntent.putExtra("stabilization", get_stabilization());
256 | mainIntent.putExtra("sensordata", get_sensordata());
257 | mainIntent.putExtra("smartcorrection", get_smartconnection());
258 |
259 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
260 | getContext().startForegroundService(mainIntent);
261 | } else {
262 | getContext().startService(mainIntent);
263 | }
264 | }
265 |
266 | public void save_data() {
267 | if (!MainActivity.hasAnySensorsAtAll())
268 | return;
269 |
270 | if (ipAddrTxt == null ||
271 | portTxt == null ||
272 | magBox == null ||
273 | madgwickBetaBox == null ||
274 | stabilizationBox == null ||
275 | sensorDataDisabled == null ||
276 | sensorDataCompat == null ||
277 | sensorDataAll == null ||
278 | smartCorrection == null)
279 | return;
280 |
281 | SharedPreferences prefs = get_prefs();
282 | SharedPreferences.Editor editor = prefs.edit();
283 |
284 | editor.putString("ip_address", get_ip_address());
285 | editor.putInt("port", get_port());
286 | editor.putBoolean("magnetometer", get_mag());
287 | editor.putFloat("madgwickbeta", get_madgwickbeta());
288 | editor.putBoolean("stabilization", get_stabilization());
289 | editor.putInt("sensordata", get_sensordata());
290 | editor.putBoolean("smartcorrection", get_smartconnection());
291 |
292 | editor.apply();
293 | }
294 | }
--------------------------------------------------------------------------------
/moveTrackMobile/src/main/java/org/moveTrack/Mobile/ui/GenericBindingFragment.java:
--------------------------------------------------------------------------------
1 | package org.moveTrack.Mobile.ui;
2 |
3 | import static android.content.Context.BIND_AUTO_CREATE;
4 |
5 | import android.content.BroadcastReceiver;
6 | import android.content.ComponentName;
7 | import android.content.Context;
8 | import android.content.Intent;
9 | import android.content.IntentFilter;
10 | import android.content.ServiceConnection;
11 | import android.os.Bundle;
12 | import android.os.IBinder;
13 | import android.view.View;
14 |
15 | import androidx.fragment.app.Fragment;
16 | import androidx.localbroadcastmanager.content.LocalBroadcastManager;
17 |
18 | import org.moveTrack.Mobile.MainActivity;
19 | import org.moveTrack.TrackingService;
20 |
21 | public abstract class GenericBindingFragment extends Fragment {
22 |
23 | public static String status_string = "";
24 | View curr_view;
25 | TrackingService service_v = null;
26 | private ServiceConnection trackingConnection = new ServiceConnection() {
27 | @Override
28 | public void onServiceConnected(ComponentName name, IBinder service) {
29 | TrackingService.TrackingBinder binderBridge = (TrackingService.TrackingBinder) service;
30 | service_v = binderBridge.getService();
31 |
32 | onConnectionStatus(service_v.is_running());
33 |
34 | if ((!service_v.is_running()) && (status_string.length() > 0)) {
35 | onSetStatus(status_string);
36 | } else {
37 | status_string = service_v.getLog();
38 | onSetStatus(status_string);
39 | }
40 | }
41 |
42 | @Override
43 | public void onServiceDisconnected(ComponentName name) {
44 | service_v = null;
45 |
46 | onConnectionStatus(false);
47 | }
48 | };
49 | private BroadcastReceiver logReceiver = new BroadcastReceiver() {
50 | @Override
51 | public void onReceive(Context context, Intent intent) {
52 | switch (intent.getAction()) {
53 | case "info-log":
54 | onConnectionStatus(true);
55 | String data = intent.getStringExtra("message");
56 | onSetStatus(data);
57 | status_string = data + "\n" + status_string;
58 | return;
59 | case "cya-ded":
60 | onConnectionStatus(false);
61 | return;
62 | case "pls-let-me-die":
63 | doBinding(false);
64 | doBinding(true);
65 | // Navigation.findNavController(curr_view).navigateUp();
66 | return;
67 |
68 | }
69 | }
70 | };
71 |
72 | protected abstract void onSetStatus(String to);
73 |
74 | protected abstract void onConnectionStatus(boolean to);
75 |
76 | private void doBinding(boolean is_bound) {
77 | if (is_bound) {
78 | Intent intent = new Intent(getContext(), TrackingService.class);
79 | getContext().bindService(intent, trackingConnection, BIND_AUTO_CREATE);
80 | } else {
81 | getContext().unbindService(trackingConnection);
82 | }
83 | }
84 |
85 | @Override
86 | public void onDestroy() {
87 | super.onDestroy();
88 | if (!MainActivity.hasAnySensorsAtAll()) return;
89 | doBinding(false);
90 | LocalBroadcastManager.getInstance(getContext()).unregisterReceiver(logReceiver);
91 | }
92 |
93 |
94 | @Override
95 | public void onCreate(Bundle savedInstanceState) {
96 | super.onCreate(savedInstanceState);
97 | if (!MainActivity.hasAnySensorsAtAll()) return;
98 |
99 | doBinding(true);
100 |
101 | LocalBroadcastManager.getInstance(getContext()).registerReceiver(logReceiver, new IntentFilter("info-log"));
102 | LocalBroadcastManager.getInstance(getContext()).registerReceiver(logReceiver, new IntentFilter("cya-ded"));
103 | LocalBroadcastManager.getInstance(getContext()).registerReceiver(logReceiver, new IntentFilter("pls-let-me-die"));
104 | }
105 | }
106 |
--------------------------------------------------------------------------------
/moveTrackMobile/src/main/java/org/moveTrack/Mobile/ui/SensorInfoFragment.java:
--------------------------------------------------------------------------------
1 | package org.moveTrack.Mobile.ui;
2 |
3 | import android.content.Context;
4 | import android.content.res.TypedArray;
5 | import android.os.Bundle;
6 | import android.util.AttributeSet;
7 | import android.view.LayoutInflater;
8 | import android.view.View;
9 | import android.view.ViewGroup;
10 | import android.widget.ImageView;
11 | import android.widget.TextView;
12 |
13 | import androidx.fragment.app.Fragment;
14 |
15 | import org.moveTrack.Mobile.MainActivity;
16 | import org.moveTrack.Mobile.R;
17 |
18 | /**
19 | * A simple {@link Fragment} subclass.
20 | * Use the {@link SensorInfoFragment#newInstance} factory method to
21 | * create an instance of this fragment.
22 | */
23 | public class SensorInfoFragment extends Fragment {
24 | String sensorName = "err";
25 | int sensorID = -2;
26 | View main_view;
27 |
28 | public SensorInfoFragment() {
29 | // Required empty public constructor
30 | }
31 |
32 | public static SensorInfoFragment newInstance(String sensorName, int sensorID) {
33 | SensorInfoFragment fragment = new SensorInfoFragment();
34 | Bundle args = new Bundle();
35 | fragment.setArguments(args);
36 | return fragment;
37 | }
38 |
39 | @Override
40 | public void onCreate(Bundle savedInstanceState) {
41 | super.onCreate(savedInstanceState);
42 |
43 | }
44 |
45 | @Override
46 | public View onCreateView(LayoutInflater inflater, ViewGroup container,
47 | Bundle savedInstanceState) {
48 | main_view = inflater.inflate(R.layout.fragment_sensor_info, container, false);
49 |
50 | if (MainActivity.getSensorExists(sensorID)) {
51 | ((ImageView) main_view.findViewById(R.id.radio_btn)).setImageResource(R.drawable.not_missing);
52 | ((TextView) main_view.findViewById(R.id.sensor_name)).setText(sensorName);
53 | } else {
54 | ((ImageView) main_view.findViewById(R.id.radio_btn)).setImageResource(R.drawable.error_missing);
55 | ((TextView) main_view.findViewById(R.id.sensor_name)).setText("Missing: " + sensorName);
56 | }
57 |
58 | return main_view;
59 | }
60 |
61 | @Override
62 | public void onInflate(Context context, AttributeSet attrs, Bundle savedInstanceState) {
63 | super.onInflate(context, attrs, savedInstanceState);
64 |
65 | TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SensorInfoFragment);
66 |
67 | sensorName = String.valueOf(a.getText(R.styleable.SensorInfoFragment_sensorName));
68 | sensorID = a.getInt(R.styleable.SensorInfoFragment_sensorID, -2);
69 |
70 | a.recycle();
71 | }
72 | }
--------------------------------------------------------------------------------
/moveTrackMobile/src/main/java/org/moveTrack/Mobile/ui/debugLogFragment.java:
--------------------------------------------------------------------------------
1 | package org.moveTrack.Mobile.ui;
2 |
3 | import android.os.Bundle;
4 | import android.view.LayoutInflater;
5 | import android.view.View;
6 | import android.view.ViewGroup;
7 |
8 | import androidx.fragment.app.Fragment;
9 |
10 | import org.moveTrack.AppStatus;
11 | import org.moveTrack.Mobile.R;
12 |
13 | /**
14 | * A simple {@link Fragment} subclass.
15 | * Use the {@link debugLogFragment#newInstance} factory method to
16 | * create an instance of this fragment.
17 | */
18 | public class debugLogFragment extends GenericBindingFragment {
19 | AppStatus stat;
20 |
21 | public debugLogFragment() {
22 | }
23 |
24 | public static debugLogFragment newInstance() {
25 | debugLogFragment fragment = new debugLogFragment();
26 | Bundle args = new Bundle();
27 | fragment.setArguments(args);
28 | return fragment;
29 | }
30 |
31 | @Override
32 | protected void onSetStatus(String to) {
33 | if (stat != null) stat.update(to);
34 | }
35 |
36 | @Override
37 | protected void onConnectionStatus(boolean to) {
38 |
39 | }
40 |
41 | @Override
42 | public View onCreateView(LayoutInflater inflater, ViewGroup container,
43 | Bundle savedInstanceState) {
44 | curr_view = inflater.inflate(R.layout.fragment_debug_log, container, false);
45 | stat = new AppStatus(getActivity(), curr_view.findViewById(R.id.debugText));
46 | return curr_view;
47 | }
48 | }
--------------------------------------------------------------------------------
/moveTrackMobile/src/main/java/org/moveTrack/Mobile/ui/homeMenu.java:
--------------------------------------------------------------------------------
1 | package org.moveTrack.Mobile.ui;
2 |
3 | import android.content.Intent;
4 | import android.os.Build;
5 | import android.os.Bundle;
6 | import android.view.LayoutInflater;
7 | import android.view.View;
8 | import android.view.ViewGroup;
9 | import android.widget.Button;
10 | import android.widget.TextView;
11 |
12 | import androidx.fragment.app.Fragment;
13 |
14 | import org.moveTrack.Mobile.MainActivity;
15 | import org.moveTrack.Mobile.R;
16 | import org.moveTrack.TrackingService;
17 |
18 | public class homeMenu extends Fragment {
19 |
20 |
21 | public homeMenu() {
22 | }
23 |
24 | @Override
25 | public void onCreate(Bundle savedInstanceState) {
26 | super.onCreate(savedInstanceState);
27 | }
28 |
29 | @Override
30 | public View onCreateView(LayoutInflater inflater, ViewGroup container,
31 | Bundle savedInstanceState) {
32 | View v = inflater.inflate(R.layout.fragment_home_menu, container, false);
33 |
34 | Button autoConnectButton = v.findViewById(R.id.autoconnectButton);
35 | TextView sensorWarning = v.findViewById(R.id.sensorWarningTextView);
36 | sensorWarning.setText(MainActivity.getSensorText());
37 |
38 | if (!MainActivity.hasAnySensorsAtAll()) {
39 | TextView sleepWarning = v.findViewById(R.id.sleepWarningText);
40 | sleepWarning.setText("");
41 | autoConnectButton.setVisibility(View.GONE);
42 | } else {
43 | autoConnectButton.setOnClickListener(p -> autoConnect());
44 | }
45 |
46 | return v;
47 | }
48 |
49 | private void autoConnect() {
50 | if (TrackingService.isInstanceCreated()) return;
51 |
52 | Intent mainIntent = new Intent(getContext(), TrackingService.class);
53 | mainIntent.putExtra("ipAddrTxt", "255.255.255.255");
54 | mainIntent.putExtra("port_no", 6969);
55 | mainIntent.putExtra("magnetometer", true);
56 | mainIntent.putExtra("madgwickbeta", 0.1f);
57 |
58 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
59 | getContext().startForegroundService(mainIntent);
60 | } else {
61 | getContext().startService(mainIntent);
62 | }
63 | MainActivity.contr.navigate(R.id.connectFragment);
64 | }
65 | }
--------------------------------------------------------------------------------
/moveTrackMobile/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
15 |
18 |
21 |
22 |
23 |
24 |
30 |
--------------------------------------------------------------------------------
/moveTrackMobile/src/main/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
10 |
15 |
20 |
25 |
30 |
35 |
40 |
45 |
50 |
55 |
60 |
65 |
70 |
75 |
80 |
85 |
90 |
95 |
100 |
105 |
110 |
115 |
120 |
125 |
130 |
135 |
140 |
145 |
150 |
155 |
160 |
165 |
170 |
171 |
--------------------------------------------------------------------------------
/moveTrackMobile/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
23 |
24 |
29 |
--------------------------------------------------------------------------------
/moveTrackMobile/src/main/res/layout/fragment_connect.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
12 |
13 |
17 |
18 |
23 |
24 |
29 |
30 |
38 |
39 |
47 |
48 |
53 |
54 |
59 |
60 |
63 |
64 |
70 |
71 |
76 |
77 |
83 |
84 |
91 |
92 |
95 |
96 |
101 |
102 |
108 |
109 |
116 |
117 |
120 |
121 |
126 |
127 |
134 |
135 |
142 |
143 |
150 |
151 |
154 |
155 |
160 |
161 |
168 |
169 |
176 |
177 |
180 |
181 |
186 |
187 |
190 |
191 |
198 |
199 |
204 |
205 |
210 |
211 |
216 |
217 |
218 |
225 |
226 |
227 |
228 |
229 |
--------------------------------------------------------------------------------
/moveTrackMobile/src/main/res/layout/fragment_debug_log.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
14 |
15 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/moveTrackMobile/src/main/res/layout/fragment_home_menu.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
16 |
17 |
24 |
25 |
30 |
31 |
36 |
37 |
43 |
44 |
52 |
53 |
61 |
62 |
70 |
71 |
72 |
73 |
74 |
75 |
80 |
81 |
82 |
--------------------------------------------------------------------------------
/moveTrackMobile/src/main/res/layout/fragment_sensor_info.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
17 |
18 |
25 |
26 |
--------------------------------------------------------------------------------
/moveTrackMobile/src/main/res/menu/main_menu.xml:
--------------------------------------------------------------------------------
1 |
2 |
23 |
--------------------------------------------------------------------------------
/moveTrackMobile/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/moveTrackMobile/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/moveTrackMobile/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Timocop/moveTrackVR/c99ab44c9fe1e34622bc63070909e88d7103eb2d/moveTrackMobile/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/moveTrackMobile/src/main/res/mipmap-hdpi/ic_launcher_background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Timocop/moveTrackVR/c99ab44c9fe1e34622bc63070909e88d7103eb2d/moveTrackMobile/src/main/res/mipmap-hdpi/ic_launcher_background.png
--------------------------------------------------------------------------------
/moveTrackMobile/src/main/res/mipmap-hdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Timocop/moveTrackVR/c99ab44c9fe1e34622bc63070909e88d7103eb2d/moveTrackMobile/src/main/res/mipmap-hdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/moveTrackMobile/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Timocop/moveTrackVR/c99ab44c9fe1e34622bc63070909e88d7103eb2d/moveTrackMobile/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/moveTrackMobile/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Timocop/moveTrackVR/c99ab44c9fe1e34622bc63070909e88d7103eb2d/moveTrackMobile/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/moveTrackMobile/src/main/res/mipmap-mdpi/ic_launcher_background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Timocop/moveTrackVR/c99ab44c9fe1e34622bc63070909e88d7103eb2d/moveTrackMobile/src/main/res/mipmap-mdpi/ic_launcher_background.png
--------------------------------------------------------------------------------
/moveTrackMobile/src/main/res/mipmap-mdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Timocop/moveTrackVR/c99ab44c9fe1e34622bc63070909e88d7103eb2d/moveTrackMobile/src/main/res/mipmap-mdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/moveTrackMobile/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Timocop/moveTrackVR/c99ab44c9fe1e34622bc63070909e88d7103eb2d/moveTrackMobile/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/moveTrackMobile/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Timocop/moveTrackVR/c99ab44c9fe1e34622bc63070909e88d7103eb2d/moveTrackMobile/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/moveTrackMobile/src/main/res/mipmap-xhdpi/ic_launcher_background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Timocop/moveTrackVR/c99ab44c9fe1e34622bc63070909e88d7103eb2d/moveTrackMobile/src/main/res/mipmap-xhdpi/ic_launcher_background.png
--------------------------------------------------------------------------------
/moveTrackMobile/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Timocop/moveTrackVR/c99ab44c9fe1e34622bc63070909e88d7103eb2d/moveTrackMobile/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/moveTrackMobile/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Timocop/moveTrackVR/c99ab44c9fe1e34622bc63070909e88d7103eb2d/moveTrackMobile/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/moveTrackMobile/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Timocop/moveTrackVR/c99ab44c9fe1e34622bc63070909e88d7103eb2d/moveTrackMobile/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/moveTrackMobile/src/main/res/mipmap-xxhdpi/ic_launcher_background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Timocop/moveTrackVR/c99ab44c9fe1e34622bc63070909e88d7103eb2d/moveTrackMobile/src/main/res/mipmap-xxhdpi/ic_launcher_background.png
--------------------------------------------------------------------------------
/moveTrackMobile/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Timocop/moveTrackVR/c99ab44c9fe1e34622bc63070909e88d7103eb2d/moveTrackMobile/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/moveTrackMobile/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Timocop/moveTrackVR/c99ab44c9fe1e34622bc63070909e88d7103eb2d/moveTrackMobile/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/moveTrackMobile/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Timocop/moveTrackVR/c99ab44c9fe1e34622bc63070909e88d7103eb2d/moveTrackMobile/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/moveTrackMobile/src/main/res/mipmap-xxxhdpi/ic_launcher_background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Timocop/moveTrackVR/c99ab44c9fe1e34622bc63070909e88d7103eb2d/moveTrackMobile/src/main/res/mipmap-xxxhdpi/ic_launcher_background.png
--------------------------------------------------------------------------------
/moveTrackMobile/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Timocop/moveTrackVR/c99ab44c9fe1e34622bc63070909e88d7103eb2d/moveTrackMobile/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/moveTrackMobile/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Timocop/moveTrackVR/c99ab44c9fe1e34622bc63070909e88d7103eb2d/moveTrackMobile/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/moveTrackMobile/src/main/res/navigation/nav_graph.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
14 |
19 |
24 |
--------------------------------------------------------------------------------
/moveTrackMobile/src/main/res/values-night/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
16 |
--------------------------------------------------------------------------------
/moveTrackMobile/src/main/res/values/attrs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/moveTrackMobile/src/main/res/values/sensors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 0
4 | 1
5 | 2
6 |
--------------------------------------------------------------------------------
/moveTrackMobile/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | moveTrackVR
3 |
4 |
5 |
6 |
7 | This app may fail to run in the background or with the screen off on some devices.
8 | Please visit https://dontkillmyapp.com/ to see solutions for your device.
9 |
10 |
11 |
12 |
13 |
14 | Unfortunately, your phone lacks the necessary sensors for this app to function.
15 | Please try another phone, or consider building DIY Slime trackers.
16 |
17 |
--------------------------------------------------------------------------------
/moveTrackMobile/src/main/res/values/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
16 |
--------------------------------------------------------------------------------
/moveTrackWear/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/moveTrackWear/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'com.android.application'
3 | }
4 |
5 | android {
6 | compileSdkVersion 31
7 |
8 | defaultConfig {
9 | applicationId 'org.movevrtrackersync'
10 | minSdkVersion 25
11 | targetSdkVersion 31
12 | versionCode 119
13 | versionName '9.7.9'
14 |
15 | }
16 |
17 | buildTypes {
18 | release {
19 | minifyEnabled false
20 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
21 | }
22 | }
23 | buildFeatures {
24 | viewBinding true
25 | }
26 | compileOptions {
27 | sourceCompatibility JavaVersion.VERSION_1_8
28 | targetCompatibility JavaVersion.VERSION_1_8
29 | }
30 | }
31 |
32 | dependencies {
33 |
34 | implementation 'com.google.android.gms:play-services-wearable:17.0.0'
35 | implementation 'androidx.percentlayout:percentlayout:1.0.0'
36 | implementation 'androidx.legacy:legacy-support-v4:1.0.0'
37 | implementation 'androidx.recyclerview:recyclerview:1.2.0'
38 | implementation 'androidx.wear:wear:1.2.0'
39 | implementation project(path: ':moveTrackLib')
40 | }
--------------------------------------------------------------------------------
/moveTrackWear/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
--------------------------------------------------------------------------------
/moveTrackWear/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
22 |
25 |
26 |
30 |
33 |
34 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
50 |
51 |
52 |
53 |
54 |
--------------------------------------------------------------------------------
/moveTrackWear/src/main/java/org/moveTrack/Wear/MainWear.java:
--------------------------------------------------------------------------------
1 | package org.moveTrack.Wear;
2 |
3 | import android.app.Activity;
4 | import android.content.BroadcastReceiver;
5 | import android.content.ComponentName;
6 | import android.content.Context;
7 | import android.content.Intent;
8 | import android.content.IntentFilter;
9 | import android.content.ServiceConnection;
10 | import android.content.SharedPreferences;
11 | import android.hardware.Sensor;
12 | import android.hardware.SensorManager;
13 | import android.net.ConnectivityManager;
14 | import android.net.Network;
15 | import android.net.NetworkCapabilities;
16 | import android.net.NetworkRequest;
17 | import android.os.Build;
18 | import android.os.Bundle;
19 | import android.os.IBinder;
20 | import android.util.Pair;
21 | import android.view.View;
22 | import android.widget.TextView;
23 |
24 | import androidx.localbroadcastmanager.content.LocalBroadcastManager;
25 |
26 | import org.moveTrack.Handshaker;
27 | import org.moveTrack.TrackingService;
28 | import org.moveTrack.Wear.databinding.ActivityMainwearBinding;
29 |
30 | import java.util.concurrent.locks.Lock;
31 | import java.util.concurrent.locks.ReentrantLock;
32 |
33 | public class MainWear extends Activity {
34 |
35 | final static String CONN_DATA = "CONNECTION_DATA_PREF";
36 | boolean gyro_exist;
37 | boolean accel_exist;
38 | boolean mag_exist;
39 | boolean connecting;
40 | boolean connected;
41 | boolean isAutoDiscover = true;
42 | TrackingService service_v = null;
43 | private ActivityMainwearBinding binding;
44 | private TextView debugText;
45 | private boolean dead_no_sensors = false;
46 | private Lock connecting_lock = new ReentrantLock();
47 | private ServiceConnection trackingConnection = new ServiceConnection() {
48 | @Override
49 | public void onServiceConnected(ComponentName name, IBinder service) {
50 | TrackingService.TrackingBinder binderBridge = (TrackingService.TrackingBinder) service;
51 | service_v = binderBridge.getService();
52 |
53 | onConnectionStatus(service_v.is_running());
54 |
55 | onSetStatus(service_v.getLog());
56 | }
57 |
58 | @Override
59 | public void onServiceDisconnected(ComponentName name) {
60 | service_v = null;
61 |
62 | onConnectionStatus(false);
63 | }
64 | };
65 | private BroadcastReceiver logReceiver = new BroadcastReceiver() {
66 | @Override
67 | public void onReceive(Context context, Intent intent) {
68 | switch (intent.getAction()) {
69 | case "info-log":
70 | onConnectionStatus(true);
71 | String data = intent.getStringExtra("message");
72 | onSetStatus(data);
73 | return;
74 | case "cya-ded":
75 | onConnectionStatus(false);
76 | return;
77 | case "pls-let-me-die":
78 | doBinding(false);
79 | doBinding(true);
80 | return;
81 |
82 | }
83 | }
84 | };
85 | private int debounce_wifi = 0;
86 | private boolean wifi_acquired = true;
87 |
88 | public static SharedPreferences get_prefs(Context c) {
89 | return c.getSharedPreferences(CONN_DATA, Context.MODE_PRIVATE);
90 | }
91 |
92 | private void onSetStatus(String to) {
93 | if (to.contains("Service not start")) return;
94 |
95 | String[] lines = to.split("\n");
96 |
97 | this.runOnUiThread(() -> {
98 | debugText.setText(lines[lines.length - 1]);
99 | });
100 | }
101 |
102 | private void onSetStatus(int rid) {
103 | onSetStatus(getString(rid));
104 | }
105 |
106 | private void onConnectionStatus(boolean to) {
107 | setConnectedStatus(connecting, to);
108 | }
109 |
110 | private void updateSensorStatus() {
111 | SensorManager man = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
112 |
113 | gyro_exist = (
114 | man.getDefaultSensor(Sensor.TYPE_GYROSCOPE) != null ||
115 | man.getDefaultSensor(Sensor.TYPE_GYROSCOPE_UNCALIBRATED) != null
116 | );
117 | accel_exist = (
118 | man.getDefaultSensor(Sensor.TYPE_ACCELEROMETER) != null ||
119 | man.getDefaultSensor(Sensor.TYPE_ACCELEROMETER_UNCALIBRATED) != null
120 | );
121 | mag_exist = man.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD) != null;
122 |
123 | this.runOnUiThread(() -> {
124 | binding.gyroSensorAvailable.setEnabled(gyro_exist);
125 | binding.accelSensorAvailable.setEnabled(accel_exist);
126 | binding.magSensorAvailable.setEnabled(mag_exist);
127 |
128 | dead_no_sensors = (!gyro_exist) && (!accel_exist);
129 | if (dead_no_sensors) {
130 | binding.yesSensorsLayout.setVisibility(View.GONE);
131 | binding.noSensorsLayout.setVisibility(View.VISIBLE);
132 | } else {
133 | binding.yesSensorsLayout.setVisibility(View.VISIBLE);
134 | binding.noSensorsLayout.setVisibility(View.GONE);
135 | }
136 | });
137 | }
138 |
139 | public SharedPreferences get_prefs() {
140 | return get_prefs(this);
141 | }
142 |
143 | private void onAutodiscoverChanged(View view) {
144 | binding.manualConnect.setVisibility(binding.autodiscover.isChecked() ? View.GONE : View.VISIBLE);
145 | isAutoDiscover = binding.autodiscover.isChecked();
146 | }
147 |
148 | private Pair getIpPort() {
149 | String filtered_ip = String.valueOf(binding.editIpAddr.getText()).replaceAll("[^0-9\\.]", "");
150 | int port = 6969;
151 | try {
152 | port = Integer.parseInt(String.valueOf(binding.editPort.getText()));
153 | } catch (NumberFormatException ignored) {
154 | }
155 |
156 | int finalPort = port;
157 | this.runOnUiThread(() -> {
158 | binding.editIpAddr.setText(filtered_ip);
159 | binding.editPort.setText(String.valueOf(finalPort));
160 | });
161 | return new Pair(filtered_ip, port);
162 | }
163 |
164 | private void load_prefs() {
165 | SharedPreferences prefs = get_prefs();
166 |
167 | this.runOnUiThread(() -> {
168 | binding.editIpAddr.setText(prefs.getString("ip", ""));
169 | binding.editPort.setText(String.valueOf(prefs.getInt("port", 6969)));
170 | binding.autodiscover.setChecked(prefs.getBoolean("autodiscover", true));
171 | });
172 | }
173 |
174 | private void save_prefs() {
175 | SharedPreferences prefs = get_prefs();
176 | SharedPreferences.Editor editor = prefs.edit();
177 |
178 | editor.putString("ip", String.valueOf(binding.editIpAddr.getText()));
179 | try {
180 | editor.putInt("port", Integer.parseInt(String.valueOf(binding.editPort.getText())));
181 | } catch (NumberFormatException ignored) {
182 | }
183 |
184 | editor.putBoolean("autodiscover", binding.autodiscover.isChecked());
185 |
186 | editor.apply();
187 | }
188 |
189 | @Override
190 | protected void onCreate(Bundle savedInstanceState) {
191 | super.onCreate(savedInstanceState);
192 |
193 | binding = ActivityMainwearBinding.inflate(getLayoutInflater());
194 |
195 | updateSensorStatus();
196 |
197 | binding.connectButton.setOnClickListener(this::connectToWifiAndRun);
198 | binding.autodiscover.setOnClickListener(this::onAutodiscoverChanged);
199 |
200 | debugText = binding.debugText;
201 |
202 | setContentView(binding.getRoot());
203 |
204 | setConnectedStatus(false, false);
205 |
206 | doBinding(true);
207 | LocalBroadcastManager.getInstance(this).registerReceiver(logReceiver, new IntentFilter("info-log"));
208 | LocalBroadcastManager.getInstance(this).registerReceiver(logReceiver, new IntentFilter("cya-ded"));
209 | LocalBroadcastManager.getInstance(this).registerReceiver(logReceiver, new IntentFilter("pls-let-me-die"));
210 |
211 | load_prefs();
212 | onAutodiscoverChanged(null);
213 |
214 | ensureUUIDSet();
215 | }
216 |
217 | @Override
218 | protected void onDestroy() {
219 | super.onDestroy();
220 | save_prefs();
221 |
222 | doBinding(false);
223 | LocalBroadcastManager.getInstance(this).unregisterReceiver(logReceiver);
224 | }
225 |
226 | private void setConnectedStatus(boolean connecting, boolean connected) {
227 | this.connecting = connecting;
228 | this.connected = connected;
229 |
230 | this.runOnUiThread(() -> {
231 | binding.spinner.setVisibility((connecting && !connected) ? View.VISIBLE : View.GONE);
232 | binding.connectButton.setVisibility((!connecting) ? View.VISIBLE : View.GONE);
233 | binding.connectButton.setEnabled(!connecting);
234 |
235 | binding.connectButton.setText(connected ? R.string.disconnect : R.string.connect);
236 | });
237 | }
238 |
239 | private void doBinding(boolean is_bound) {
240 | if (is_bound) {
241 | Intent intent = new Intent(this, TrackingService.class);
242 | this.bindService(intent, trackingConnection, BIND_AUTO_CREATE);
243 | } else {
244 | this.unbindService(trackingConnection);
245 | }
246 | }
247 |
248 | private void connect(String ip, int port) {
249 | onConnectionStatus(true);
250 |
251 | Intent mainIntent = new Intent(this, TrackingService.class);
252 | mainIntent.putExtra("ipAddrTxt", ip);
253 | mainIntent.putExtra("port_no", port);
254 |
255 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
256 | this.startForegroundService(mainIntent);
257 | } else {
258 | this.startService(mainIntent);
259 | }
260 | }
261 |
262 | private void ensureUUIDSet() {
263 | SharedPreferences prefs = getSharedPreferences("FakeMACWear", Context.MODE_PRIVATE);
264 |
265 | long val = -1;
266 | if (!prefs.contains("FakeMACValueWear")) {
267 | SharedPreferences.Editor editor = prefs.edit();
268 | val = (new java.util.Random()).nextLong();
269 | editor.putLong("FakeMACValueWear", val);
270 | editor.apply();
271 | } else {
272 | val = prefs.getLong("FakeMACValueWear", 1);
273 | }
274 |
275 | Handshaker.setMac(val);
276 | }
277 |
278 | private void runConnectionProcedure() {
279 | if (!connecting_lock.tryLock()) return;
280 |
281 | boolean server_found = false;
282 | try {
283 | onSetStatus(R.string.searching);
284 |
285 | if (isAutoDiscover) {
286 | this.connect("255.255.255.255", 6969);
287 | } else {
288 | Pair ipPort = getIpPort();
289 | if (ipPort.first.length() < 3) {
290 | onSetStatus("Please enter valid IP");
291 | return;
292 | }
293 |
294 | server_found = true;
295 | this.connect(ipPort.first, ipPort.second);
296 | }
297 | } finally {
298 | connecting_lock.unlock();
299 | boolean finalServer_found = server_found;
300 | this.runOnUiThread(() -> {
301 | setConnectedStatus(false, finalServer_found);
302 | });
303 | }
304 | }
305 |
306 | private void connectToWifiAndRun(View view) {
307 | if (dead_no_sensors) return;
308 |
309 | if ((service_v != null) && (service_v.is_running())) {
310 | onSetStatus("Killing service...");
311 | Intent intent = new Intent("kill-ze-service");
312 | this.sendBroadcast(intent);
313 |
314 | setConnectedStatus(false, false);
315 | return;
316 | }
317 |
318 | if (debounce_wifi > 0 && !wifi_acquired) {
319 | this.startActivity(new Intent("com.google.android.clockwork.settings.connectivity.wifi.ADD_NETWORK_SETTINGS"));
320 | }
321 |
322 |
323 | debounce_wifi++;
324 | int curr_deb = debounce_wifi;
325 | wifi_acquired = false;
326 |
327 |
328 | onSetStatus("Awaiting WiFi network...");
329 |
330 | ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
331 | ConnectivityManager.NetworkCallback callback = new ConnectivityManager.NetworkCallback() {
332 | public void onAvailable(Network network) {
333 | if (curr_deb != debounce_wifi) return;
334 | wifi_acquired = true;
335 |
336 | super.onAvailable(network);
337 |
338 | // The Wi-Fi network has been acquired, bind it to use this network by default
339 | connectivityManager.bindProcessToNetwork(network);
340 |
341 | runOnUiThread(() -> {
342 | onConnectClick(view, network);
343 | });
344 | }
345 | };
346 | connectivityManager.requestNetwork(
347 | new NetworkRequest.Builder().addTransportType(NetworkCapabilities.TRANSPORT_WIFI).build(),
348 | callback
349 | );
350 | }
351 |
352 | private void onConnectClick(View view, Network network) {
353 | setConnectedStatus(true, false);
354 |
355 | Thread thread = new Thread(this::runConnectionProcedure);
356 | thread.start();
357 | }
358 | }
--------------------------------------------------------------------------------
/moveTrackWear/src/main/res/layout/activity_mainwear.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
14 |
15 |
20 |
21 |
27 |
28 |
36 |
37 |
42 |
43 |
44 |
50 |
51 |
56 |
57 |
66 |
67 |
76 |
77 |
86 |
87 |
88 |
89 |
90 |
95 |
96 |
101 |
102 |
109 |
110 |
116 |
117 |
126 |
127 |
137 |
138 |
139 |
140 |
141 |
146 |
147 |
153 |
154 |
159 |
160 |
165 |
166 |
167 |
168 |
169 |
175 |
176 |
181 |
182 |
183 |
184 |
185 |
186 |
--------------------------------------------------------------------------------
/moveTrackWear/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/moveTrackWear/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/moveTrackWear/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Timocop/moveTrackVR/c99ab44c9fe1e34622bc63070909e88d7103eb2d/moveTrackWear/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/moveTrackWear/src/main/res/mipmap-hdpi/ic_launcher_background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Timocop/moveTrackVR/c99ab44c9fe1e34622bc63070909e88d7103eb2d/moveTrackWear/src/main/res/mipmap-hdpi/ic_launcher_background.png
--------------------------------------------------------------------------------
/moveTrackWear/src/main/res/mipmap-hdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Timocop/moveTrackVR/c99ab44c9fe1e34622bc63070909e88d7103eb2d/moveTrackWear/src/main/res/mipmap-hdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/moveTrackWear/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Timocop/moveTrackVR/c99ab44c9fe1e34622bc63070909e88d7103eb2d/moveTrackWear/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/moveTrackWear/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Timocop/moveTrackVR/c99ab44c9fe1e34622bc63070909e88d7103eb2d/moveTrackWear/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/moveTrackWear/src/main/res/mipmap-mdpi/ic_launcher_background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Timocop/moveTrackVR/c99ab44c9fe1e34622bc63070909e88d7103eb2d/moveTrackWear/src/main/res/mipmap-mdpi/ic_launcher_background.png
--------------------------------------------------------------------------------
/moveTrackWear/src/main/res/mipmap-mdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Timocop/moveTrackVR/c99ab44c9fe1e34622bc63070909e88d7103eb2d/moveTrackWear/src/main/res/mipmap-mdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/moveTrackWear/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Timocop/moveTrackVR/c99ab44c9fe1e34622bc63070909e88d7103eb2d/moveTrackWear/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/moveTrackWear/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Timocop/moveTrackVR/c99ab44c9fe1e34622bc63070909e88d7103eb2d/moveTrackWear/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/moveTrackWear/src/main/res/mipmap-xhdpi/ic_launcher_background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Timocop/moveTrackVR/c99ab44c9fe1e34622bc63070909e88d7103eb2d/moveTrackWear/src/main/res/mipmap-xhdpi/ic_launcher_background.png
--------------------------------------------------------------------------------
/moveTrackWear/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Timocop/moveTrackVR/c99ab44c9fe1e34622bc63070909e88d7103eb2d/moveTrackWear/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/moveTrackWear/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Timocop/moveTrackVR/c99ab44c9fe1e34622bc63070909e88d7103eb2d/moveTrackWear/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/moveTrackWear/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Timocop/moveTrackVR/c99ab44c9fe1e34622bc63070909e88d7103eb2d/moveTrackWear/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/moveTrackWear/src/main/res/mipmap-xxhdpi/ic_launcher_background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Timocop/moveTrackVR/c99ab44c9fe1e34622bc63070909e88d7103eb2d/moveTrackWear/src/main/res/mipmap-xxhdpi/ic_launcher_background.png
--------------------------------------------------------------------------------
/moveTrackWear/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Timocop/moveTrackVR/c99ab44c9fe1e34622bc63070909e88d7103eb2d/moveTrackWear/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/moveTrackWear/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Timocop/moveTrackVR/c99ab44c9fe1e34622bc63070909e88d7103eb2d/moveTrackWear/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/moveTrackWear/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Timocop/moveTrackVR/c99ab44c9fe1e34622bc63070909e88d7103eb2d/moveTrackWear/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/moveTrackWear/src/main/res/mipmap-xxxhdpi/ic_launcher_background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Timocop/moveTrackVR/c99ab44c9fe1e34622bc63070909e88d7103eb2d/moveTrackWear/src/main/res/mipmap-xxxhdpi/ic_launcher_background.png
--------------------------------------------------------------------------------
/moveTrackWear/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Timocop/moveTrackVR/c99ab44c9fe1e34622bc63070909e88d7103eb2d/moveTrackWear/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/moveTrackWear/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Timocop/moveTrackVR/c99ab44c9fe1e34622bc63070909e88d7103eb2d/moveTrackWear/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/moveTrackWear/src/main/res/values-round/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Hello Round World!
3 |
--------------------------------------------------------------------------------
/moveTrackWear/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 | 0dp
8 |
9 |
14 | 5dp
15 |
--------------------------------------------------------------------------------
/moveTrackWear/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | moveTrackWear
3 |
7 | Hello Square World!
8 | moveTrack
9 | Available sensors
10 | Mag. Sensor
11 | Accel. Sensor
12 | Gyro. Sensor
13 | Connect
14 |
15 | Searching…
16 | No server found
17 |
18 | Broadcasting
19 | Connected
20 | No compatible sensors have been found on this watch :(
21 |
22 | Disconnect
23 | Autodiscover
24 | IP address
25 | Connection
26 | Port
27 | You will be automatically connected to WiFi
28 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':moveTrackLib'
2 | rootProject.name = "moveTrack"
3 | include ':moveTrackMobile'
4 | include ':moveTrackWear'
5 |
--------------------------------------------------------------------------------