├── .gitignore ├── CHANGELOG ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── pictures ├── App-UI.jpeg └── a ├── pyproject.toml ├── sensor-server.py ├── src ├── __init__.py └── sensorapp │ ├── __init__.py │ ├── __main__.py │ ├── app.py │ └── resources │ ├── __init__.py │ ├── sensorapp.icns │ ├── sensorapp.ico │ └── sensorapp.png └── tests ├── __init__.py ├── sensorapp.py └── test_app.py /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # OSX useful to ignore 7 | *.DS_Store 8 | .AppleDouble 9 | .LSOverride 10 | 11 | # Thumbnails 12 | ._* 13 | 14 | # Files that might appear in the root of a volume 15 | .DocumentRevisions-V100 16 | .fseventsd 17 | .Spotlight-V100 18 | .TemporaryItems 19 | .Trashes 20 | .VolumeIcon.icns 21 | .com.apple.timemachine.donotpresent 22 | 23 | # Directories potentially created on remote AFP share 24 | .AppleDB 25 | .AppleDesktop 26 | Network Trash Folder 27 | Temporary Items 28 | .apdisk 29 | 30 | # C extensions 31 | *.so 32 | 33 | # Distribution / packaging 34 | .Python 35 | env/ 36 | build/ 37 | develop-eggs/ 38 | dist/ 39 | downloads/ 40 | eggs/ 41 | .eggs/ 42 | lib/ 43 | lib64/ 44 | parts/ 45 | sdist/ 46 | var/ 47 | *.dist-info/ 48 | *.egg-info/ 49 | .installed.cfg 50 | *.egg 51 | 52 | # IntelliJ Idea family of suites 53 | .idea 54 | *.iml 55 | ## File-based project format: 56 | *.ipr 57 | *.iws 58 | ## mpeltonen/sbt-idea plugin 59 | .idea_modules/ 60 | 61 | # Briefcase log files 62 | logs/ 63 | -------------------------------------------------------------------------------- /CHANGELOG: -------------------------------------------------------------------------------- 1 | # Sensor-App Release Notes 2 | 3 | ## 0.0.1 (21 Apr 2024) 4 | 5 | * Initial release 6 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | When contributing to this repository, please first discuss the change you wish to make via issue, 4 | email, or any other method with the owners of this repository before making a change. 5 | 6 | Please note we have a code of conduct, please follow it in all your interactions with the project. 7 | 8 | ## Pull Request Process 9 | 10 | 1. Ensure any install or build dependencies are removed before the end of the layer when doing a 11 | build. 12 | 2. Update the README.md with details of changes to the interface, this includes new environment 13 | variables, exposed ports, useful file locations and container parameters. 14 | 3. Increase the version numbers in any examples files and the README.md to the new version that this 15 | Pull Request would represent. The versioning scheme we use is [SemVer](http://semver.org/). 16 | 4. You may merge the Pull Request in once you have the sign-off of two other developers, or if you 17 | do not have permission to do that, you may request the second reviewer to merge it for you. 18 | 19 | ## Code of Conduct 20 | 21 | ### Our Pledge 22 | 23 | In the interest of fostering an open and welcoming environment, we as 24 | contributors and maintainers pledge to making participation in our project and 25 | our community a harassment-free experience for everyone, regardless of age, body 26 | size, disability, ethnicity, gender identity and expression, level of experience, 27 | nationality, personal appearance, race, religion, or sexual identity and 28 | orientation. 29 | 30 | ### Our Standards 31 | 32 | Examples of behavior that contributes to creating a positive environment 33 | include: 34 | 35 | * Using welcoming and inclusive language 36 | * Being respectful of differing viewpoints and experiences 37 | * Gracefully accepting constructive criticism 38 | * Focusing on what is best for the community 39 | * Showing empathy towards other community members 40 | 41 | Examples of unacceptable behavior by participants include: 42 | 43 | * The use of sexualized language or imagery and unwelcome sexual attention or 44 | advances 45 | * Trolling, insulting/derogatory comments, and personal or political attacks 46 | * Public or private harassment 47 | * Publishing others' private information, such as a physical or electronic 48 | address, without explicit permission 49 | * Other conduct which could reasonably be considered inappropriate in a 50 | professional setting 51 | 52 | ### Our Responsibilities 53 | 54 | Project maintainers are responsible for clarifying the standards of acceptable 55 | behavior and are expected to take appropriate and fair corrective action in 56 | response to any instances of unacceptable behavior. 57 | 58 | Project maintainers have the right and responsibility to remove, edit, or 59 | reject comments, commits, code, wiki edits, issues, and other contributions 60 | that are not aligned to this Code of Conduct, or to ban temporarily or 61 | permanently any contributor for other behaviors that they deem inappropriate, 62 | threatening, offensive, or harmful. 63 | 64 | ### Scope 65 | 66 | This Code of Conduct applies both within project spaces and in public spaces 67 | when an individual is representing the project or its community. Examples of 68 | representing a project or community include using an official project e-mail 69 | address, posting via an official social media account, or acting as an appointed 70 | representative at an online or offline event. Representation of a project may be 71 | further defined and clarified by project maintainers. 72 | 73 | ### Enforcement 74 | 75 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 76 | reported by contacting the project team at [INSERT EMAIL ADDRESS]. All 77 | complaints will be reviewed and investigated and will result in a response that 78 | is deemed necessary and appropriate to the circumstances. The project team is 79 | obligated to maintain confidentiality with regard to the reporter of an incident. 80 | Further details of specific enforcement policies may be posted separately. 81 | 82 | Project maintainers who do not follow or enforce the Code of Conduct in good 83 | faith may face temporary or permanent repercussions as determined by other 84 | members of the project's leadership. 85 | 86 | ### Attribution 87 | 88 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 89 | available at [http://contributor-covenant.org/version/1/4][version] 90 | 91 | [homepage]: http://contributor-covenant.org 92 | [version]: http://contributor-covenant.org/version/1/4/ 93 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2024, StoneSteel27 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Sensor-App 2 | ========== 3 | 4 | **This cross-platform app was generated by** `Briefcase` **part of** 5 | `The BeeWare Project`. 6 | 7 | A Sensor Data Displaying/Streaming Android App built with Beeware tools. 8 | 9 | ## Features 10 | - Real-Time Display of Sensor Data 11 | - Fast Real-Time Sensor Data Streaming via TCP Sockets 12 | 13 | ## Data Stream Setup 14 | - This Repository contains `sensor-server.py` python file which provides a simple way for creating the Server. 15 | - The Communication between the App and the Server will happen on port-`5678`. 16 | - Start the server using: 17 | ```bash 18 | $ python sensor-server.py 19 | ``` 20 | - Obtain your server's local IP address and enter in the App to Start the Data Stream. 21 | 22 | ## App's Preview 23 | 24 | 25 | ## Building From Source 26 | - First, Clone the Repo 27 | ```bash 28 | $ git clone https://github.com/StoneSteel27/SensorApp 29 | $ cd SensorApp 30 | ``` 31 | - Install `Briefcase` 32 | ```bash 33 | $ pip install briefcase 34 | ``` 35 | - Start the Building Process with: 36 | ```bash 37 | $ briefcase build android 38 | ``` 39 | - Finally, the last line of build process, will contain the path to the `apk` file 40 | 41 | ## Background 42 | - Sensor-App was created to aid Computer Programmers, Data Scientists with Real-Time Sensor Data, for various applications like VR and AR. 43 | - It was also made as a Introductory Project of using Tools of `Beeware`. 44 | -------------------------------------------------------------------------------- /pictures/App-UI.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StoneSteel27/SensorApp/62d861258813f3f54ea8329bd8726e298f2a7b6b/pictures/App-UI.jpeg -------------------------------------------------------------------------------- /pictures/a: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | # This project was generated with 0.3.17 using template: https://github.com/beeware/briefcase-template@v0.3.17 2 | [tool.briefcase] 3 | project_name = "Sensor-App" 4 | bundle = "com.moltensteel.sensorapp" 5 | version = "0.0.1" 6 | url = "https://moltensteel.com/sensorapp" 7 | license = "MIT license" 8 | author = "StoneSteel27" 9 | author_email = "stonesteel27@gmail.com" 10 | 11 | [tool.briefcase.app.sensorapp] 12 | formal_name = "Sensor-App" 13 | description = "A Sensor Displaying Android App built with Beeware" 14 | long_description = """More details about the app should go here. 15 | """ 16 | icon = "src/sensorapp/resources/sensorapp" 17 | sources = [ 18 | "src/sensorapp", 19 | ] 20 | test_sources = [ 21 | "tests", 22 | ] 23 | 24 | requires = [ 25 | ] 26 | test_requires = [ "pytest",] 27 | 28 | 29 | [tool.briefcase.app.sensorapp.macOS] 30 | universal_build = true 31 | requires = [ 32 | "toga-cocoa~=0.4.0", 33 | "std-nslog~=1.0.0", 34 | ] 35 | 36 | 37 | [tool.briefcase.app.sensorapp.linux] 38 | requires = [ 39 | "toga-gtk~=0.4.0", 40 | ] 41 | 42 | 43 | [tool.briefcase.app.sensorapp.linux.system.debian] 44 | system_requires = [ 45 | # Needed to compile pycairo wheel 46 | "libcairo2-dev", 47 | # Needed to compile PyGObject wheel 48 | "libgirepository1.0-dev", 49 | ] 50 | 51 | system_runtime_requires = [ 52 | # Needed to provide GTK and its GI bindings 53 | "gir1.2-gtk-3.0", 54 | "libgirepository-1.0-1", 55 | # Dependencies that GTK looks for at runtime 56 | "libcanberra-gtk3-module", 57 | # Needed to provide WebKit2 at runtime 58 | # "gir1.2-webkit2-4.0", 59 | ] 60 | 61 | 62 | [tool.briefcase.app.sensorapp.linux.system.rhel] 63 | system_requires = [ 64 | # Needed to compile pycairo wheel 65 | "cairo-gobject-devel", 66 | # Needed to compile PyGObject wheel 67 | "gobject-introspection-devel", 68 | ] 69 | 70 | system_runtime_requires = [ 71 | # Needed to support Python bindings to GTK 72 | "gobject-introspection", 73 | # Needed to provide GTK 74 | "gtk3", 75 | # Dependencies that GTK looks for at runtime 76 | "libcanberra-gtk3", 77 | # Needed to provide WebKit2 at runtime 78 | # "webkit2gtk3", 79 | ] 80 | 81 | 82 | [tool.briefcase.app.sensorapp.linux.system.suse] 83 | system_requires = [ 84 | # Needed to compile pycairo wheel 85 | "cairo-devel", 86 | # Needed to compile PyGObject wheel 87 | "gobject-introspection-devel", 88 | ] 89 | 90 | system_runtime_requires = [ 91 | # Needed to provide GTK 92 | "gtk3", 93 | # Needed to support Python bindings to GTK 94 | "gobject-introspection", "typelib(Gtk) = 3.0", 95 | # Dependencies that GTK looks for at runtime 96 | "libcanberra-gtk3-0", 97 | # Needed to provide WebKit2 at runtime 98 | # "libwebkit2gtk3", 99 | # "typelib(WebKit2)", 100 | ] 101 | 102 | 103 | [tool.briefcase.app.sensorapp.linux.system.arch] 104 | system_requires = [ 105 | # Needed to compile pycairo wheel 106 | "cairo", 107 | # Needed to compile PyGObject wheel 108 | "gobject-introspection", 109 | # Runtime dependencies that need to exist so that the 110 | # Arch package passes final validation. 111 | # Needed to provide GTK 112 | "gtk3", 113 | # Dependencies that GTK looks for at runtime 114 | "libcanberra", 115 | # Needed to provide WebKit2 116 | # "webkit2gtk", 117 | ] 118 | 119 | system_runtime_requires = [ 120 | # Needed to provide GTK 121 | "gtk3", 122 | # Needed to provide PyGObject bindings 123 | "gobject-introspection-runtime", 124 | # Dependencies that GTK looks for at runtime 125 | "libcanberra", 126 | # Needed to provide WebKit2 at runtime 127 | # "webkit2gtk", 128 | ] 129 | 130 | 131 | [tool.briefcase.app.sensorapp.linux.appimage] 132 | manylinux = "manylinux_2_28" 133 | 134 | system_requires = [ 135 | # Needed to compile pycairo wheel 136 | "cairo-gobject-devel", 137 | # Needed to compile PyGObject wheel 138 | "gobject-introspection-devel", 139 | # Needed to provide GTK 140 | "gtk3-devel", 141 | # Dependencies that GTK looks for at runtime, that need to be 142 | # in the build environment to be picked up by linuxdeploy 143 | "libcanberra-gtk3", 144 | "PackageKit-gtk3-module", 145 | "gvfs-client", 146 | ] 147 | 148 | linuxdeploy_plugins = [ 149 | "DEPLOY_GTK_VERSION=3 gtk", 150 | ] 151 | 152 | 153 | [tool.briefcase.app.sensorapp.linux.flatpak] 154 | flatpak_runtime = "org.gnome.Platform" 155 | flatpak_runtime_version = "45" 156 | flatpak_sdk = "org.gnome.Sdk" 157 | 158 | 159 | [tool.briefcase.app.sensorapp.windows] 160 | requires = [ 161 | "toga-winforms~=0.4.0", 162 | ] 163 | 164 | 165 | # Mobile deployments 166 | [tool.briefcase.app.sensorapp.iOS] 167 | requires = [ 168 | "toga-iOS~=0.4.0", 169 | "std-nslog~=1.0.0", 170 | ] 171 | 172 | 173 | [tool.briefcase.app.sensorapp.android] 174 | requires = [ 175 | "toga-android~=0.4.0", 176 | ] 177 | 178 | base_theme = "Theme.MaterialComponents.Light.DarkActionBar" 179 | 180 | build_gradle_dependencies = [ 181 | "androidx.appcompat:appcompat:1.6.1", 182 | "com.google.android.material:material:1.11.0", 183 | # Needed for DetailedList 184 | "androidx.swiperefreshlayout:swiperefreshlayout:1.1.0", 185 | ] 186 | 187 | 188 | # Web deployments 189 | [tool.briefcase.app.sensorapp.web] 190 | requires = [ 191 | "toga-web~=0.4.0", 192 | ] 193 | style_framework = "Shoelace v2.3" 194 | 195 | 196 | -------------------------------------------------------------------------------- /sensor-server.py: -------------------------------------------------------------------------------- 1 | import socket 2 | 3 | serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 4 | serversocket.settimeout(10) 5 | serversocket.bind(('0.0.0.0', 5678)) 6 | serversocket.listen(1) 7 | 8 | connection, address = serversocket.accept() 9 | while True: 10 | buf = connection.recv(100) # size of each sensor data packet 11 | if len(buf) > 0: 12 | data = (buf.decode().replace(" ","")) 13 | d = data.split(":") 14 | t = d[0] 15 | x = d[1].split(",")[0] 16 | y = d[1].split(",")[1] 17 | z = d[1].split(",")[2] 18 | print("timestamp:",t.ljust(20),"|X:",x.ljust(20),"|Y:",y.ljust(20),"|Z:",z.ljust(20),end="\r") 19 | 20 | -------------------------------------------------------------------------------- /src/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StoneSteel27/SensorApp/62d861258813f3f54ea8329bd8726e298f2a7b6b/src/__init__.py -------------------------------------------------------------------------------- /src/sensorapp/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StoneSteel27/SensorApp/62d861258813f3f54ea8329bd8726e298f2a7b6b/src/sensorapp/__init__.py -------------------------------------------------------------------------------- /src/sensorapp/__main__.py: -------------------------------------------------------------------------------- 1 | from sensorapp.app import main 2 | 3 | if __name__ == "__main__": 4 | main().main_loop() 5 | 6 | -------------------------------------------------------------------------------- /src/sensorapp/app.py: -------------------------------------------------------------------------------- 1 | """ 2 | A Sensor Displaying Android App built with Beeware 3 | """ 4 | import socket 5 | import time 6 | import asyncio 7 | import toga 8 | from toga.style import Pack 9 | from android.widget import Toast 10 | from android.os import HandlerThread, Handler 11 | from toga.style.pack import COLUMN, ROW, LEFT, RIGHT, CENTER 12 | from android.content import Context 13 | from android.hardware import Sensor, SensorEvent, SensorEventListener, SensorManager 14 | from java import dynamic_proxy 15 | from java.lang import Runnable, Thread 16 | import threading 17 | 18 | port = 5678 19 | 20 | 21 | # noinspection PyAttributeOutsideInit 22 | class JavaFunc(dynamic_proxy(Runnable)): 23 | def __init__(self, func, *args, **kwargs): 24 | super().__init__() 25 | self.func = func 26 | self.args = args 27 | self.kwargs = kwargs 28 | 29 | def run(self): 30 | self.func(*self.args, **self.kwargs) 31 | 32 | 33 | class AccelerometerSocketListener(dynamic_proxy(SensorEventListener)): 34 | def set_app(self, app): 35 | self.app = app 36 | self.label_x = app.x_value 37 | self.label_y = app.y_value 38 | self.label_z = app.z_value 39 | self.streaming_mode = True 40 | self.count = 0 41 | self.i = 0 42 | self.j = 0 43 | 44 | def onSensorChanged(self, event): 45 | # Get the x, y, and z values of the accelerometer 46 | x = event.values[0] 47 | y = event.values[1] 48 | z = event.values[2] 49 | 50 | 51 | 52 | def onAccuracyChanged(self, sensor, accuracy): 53 | pass # You can handle changes in the accuracy of the sensor 54 | 55 | class AccelerometerUIListener(dynamic_proxy(SensorEventListener)): 56 | def set_app(self, app): 57 | self.app = app 58 | self.label_x = app.x_value 59 | self.label_y = app.y_value 60 | self.label_z = app.z_value 61 | self.streaming_mode = True 62 | self.j = 0 63 | 64 | def onSensorChanged(self, event): 65 | # Get the x, y, and z values of the accelerometer 66 | x = event.values[0] 67 | y = event.values[1] 68 | z = event.values[2] 69 | 70 | if self.app.connection: 71 | if self.j == 0: 72 | t = "Streaming..".rjust(20) 73 | self.app._impl.native.runOnUiThread( 74 | JavaFunc(self.app.set_values, t,t,t)) 75 | self.j = 1 76 | try: 77 | self.app.socket.send(f"{time.time()}:{x},{y},{z}".rjust(100).encode("utf-8")) 78 | except Exception as e: 79 | self.app._impl.native.runOnUiThread(JavaFunc(self.app.stop_connection)) 80 | message = str(e).split("] ")[1] 81 | self.app._impl.native.runOnUiThread(JavaFunc(self.app.make_toast, message)) 82 | 83 | 84 | if not self.app.connection: 85 | self.j = 0 86 | self.app._impl.native.runOnUiThread( 87 | JavaFunc(self.app.set_values, f"{x:.2f}".rjust(30), f"{y:.2f}".rjust(30), f"{z:.2f}".rjust(30))) 88 | 89 | 90 | def onAccuracyChanged(self, sensor, accuracy): 91 | pass # You can handle changes in the accuracy of the sensor here 92 | 93 | 94 | 95 | 96 | class T(dynamic_proxy(Runnable)): 97 | def __init__(self, app): 98 | super().__init__() 99 | self.app = app 100 | 101 | def run(self): 102 | if not self.app.connection: 103 | try: 104 | self.app._impl.native.runOnUiThread(JavaFunc(self.app.connecting)) 105 | self.app.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 106 | self.app.socket.connect((self.app.ip_input.value, port)) 107 | self.app.socket.setblocking(False) 108 | self.app._impl.native.runOnUiThread(JavaFunc(self.app.initialize_connection)) 109 | except Exception as e: 110 | message = str(e).split("] ")[1] 111 | self.app._impl.native.runOnUiThread(JavaFunc(self.app.make_toast, message)) 112 | self.app._impl.native.runOnUiThread(JavaFunc(self.app.stop_connection)) 113 | else: 114 | self.app._impl.native.runOnUiThread(JavaFunc(self.app.stop_connection)) 115 | 116 | 117 | class SensorApp(toga.App): 118 | def startup(self): 119 | """Construct and show the Toga application. 120 | 121 | Usually, you would add your application to a main content box. 122 | We then create a main window (with a name matching the app), and 123 | show the main window. 124 | """ 125 | self.connection = False 126 | self.acc = None 127 | self.mHandlerThread = None 128 | 129 | self.main_window = toga.MainWindow(title="Sensor App") 130 | 131 | self.context = self._impl.native.getApplicationContext() 132 | 133 | main_box = toga.Box(style=Pack(direction=COLUMN, background_color="#313135")) 134 | self.nav_box = toga.Box() 135 | self.content_box = toga.Box( 136 | style=Pack(direction=COLUMN, alignment=CENTER, padding=(10, 20), background_color="black")) 137 | 138 | self.nav_button = toga.Button("Back to Home", style=Pack(background_color="#8585ad", color="#313135"), 139 | on_press=self.navigate) 140 | self.nav_box.add(self.nav_button) 141 | 142 | self.content_label = toga.Label("Accelerometer", style=Pack(color="white", text_align=CENTER, font_size=20)) 143 | self.content = toga.Box(style=Pack(direction=COLUMN, background_color="#5A5A6C", alignment=CENTER, padding=30)) 144 | content_font_size = 18 145 | 146 | label_style = Pack(text_align=LEFT, font_size=content_font_size, color="white") 147 | value_style = Pack(font_size=content_font_size, color="white", text_align=RIGHT) 148 | data_box_style = Pack(padding=(10, 10), alignment=CENTER) 149 | self.x_box = toga.Box(style=data_box_style) 150 | self.x_label = toga.Label("X :", style=label_style) 151 | self.x_value = toga.Label("5", style=value_style) 152 | 153 | self.y_box = toga.Box(style=data_box_style) 154 | self.y_label = toga.Label("Y :", style=label_style) 155 | self.y_value = toga.Label("5", style=value_style) 156 | 157 | self.z_box = toga.Box(style=data_box_style) 158 | self.z_label = toga.Label("Z :", style=label_style) 159 | self.z_value = toga.Label("5", style=value_style) 160 | 161 | self.x_box.add(self.x_label) 162 | self.x_box.add(self.x_value) 163 | self.y_box.add(self.y_label) 164 | self.y_box.add(self.y_value) 165 | self.z_box.add(self.z_label) 166 | self.z_box.add(self.z_value) 167 | 168 | self.content.add(self.x_box, self.y_box, self.z_box) 169 | self.content_box.add(self.content_label, self.content) 170 | info_box = toga.Box(style=Pack(direction=COLUMN, padding=(0, 20))) 171 | info_label1 = toga.Label("*Speed of Sensor is reduced to save App ",style=Pack(color="orange", text_align=LEFT,font_size=9)) 172 | info_label2 = toga.Label("resources and will be increased while Streaming", 173 | style=Pack(color="orange", text_align=LEFT, font_size=9)) 174 | info_box.add(info_label1, info_label2) 175 | self.content_box.add(info_box) 176 | self.ip_box = toga.Box(style=Pack(direction=COLUMN, padding=(0, 20))) 177 | self.ip_label = toga.Label("IP Address of Server :", style=Pack(font_size=16, padding_top=10, color="white")) 178 | self.ip_input = toga.TextInput(placeholder="Enter your Server IP", 179 | style=Pack(font_size=16, background_color="white", 180 | color="black")) 181 | self.ip_button = toga.Button("Connect Server", style=Pack(background_color="#8585ad", color="#313135"), 182 | on_press=self.handle_client) 183 | self.con_box = toga.Box(style=Pack(direction=ROW, padding=(0, 20))) 184 | self.con_status_label = toga.Label("Connection Status:", style=Pack(font_size=14, color="white")) 185 | self.con_status = toga.Label("Disconnected", style=Pack(font_size=14, color="red")) 186 | self.con_box.add(self.con_status_label, self.con_status) 187 | 188 | self.ip_box.add(self.ip_label, self.ip_input, self.ip_button) 189 | self.content_box.add(self.ip_box, self.con_box) 190 | main_box.add(self.nav_box) 191 | main_box.add(self.content_box) 192 | 193 | self.start_accelerometer() 194 | 195 | self.main_window.content = main_box 196 | self.main_window.show() 197 | 198 | def navigate(self, widget): 199 | self.make_toast("Not Implemented yet") 200 | 201 | async def handle_client(self, widget): 202 | t = Thread(T(self)) 203 | t.start() 204 | 205 | def start_accelerometer(self, mode=SensorManager.SENSOR_DELAY_NORMAL): 206 | self.sensor_manager = (self.app.context.getSystemService(Context.SENSOR_SERVICE)) 207 | acc = self.sensor_manager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER) 208 | self.acc = AccelerometerUIListener() 209 | self.acc.set_app(self) 210 | self.mHandlerThread = HandlerThread("AccelerometerUIListener") 211 | self.mHandlerThread.start() 212 | self.handler = Handler(self.mHandlerThread.getLooper()) 213 | self.sensor_manager.registerListener(self.acc, acc, mode, self.handler) 214 | 215 | def stop_accelerometer(self): 216 | if self.acc: 217 | self.sensor_manager.unregisterListener(self.acc) 218 | self.acc = None 219 | 220 | if self.mHandlerThread: 221 | if self.mHandlerThread.isAlive(): 222 | self.mHandlerThread.quitSafely() 223 | self.mHandlerThread = None 224 | 225 | def initialize_connection(self): 226 | self.connection = True 227 | if self.acc and self.mHandlerThread: 228 | self.stop_accelerometer() 229 | self.start_accelerometer(mode=SensorManager.SENSOR_DELAY_GAME) 230 | self.con_status.text = "Connected" 231 | self.con_status.style.update(color="green") 232 | self.ip_button.text = "Stop Connection" 233 | 234 | def connecting(self): 235 | self.con_status.text = "Connecting.." 236 | self.con_status.style.update(color="orange") 237 | 238 | def stop_connection(self): 239 | self.connection = False 240 | if self.acc and self.mHandlerThread: 241 | self.stop_accelerometer() 242 | self.start_accelerometer() 243 | self.con_status.text = "Disconnected" 244 | self.con_status.style.update(color="red") 245 | if self.socket: 246 | self.socket.close() 247 | self.socket = None 248 | self.ip_button.text = "Connect Server" 249 | 250 | def make_toast(self, text): 251 | #print(text) 252 | Toast.makeText(self.context, text, Toast.LENGTH_SHORT).show() 253 | 254 | def set_values(self, x, y, z): 255 | self.x_value.text = x 256 | self.y_value.text = y 257 | self.z_value.text = z 258 | 259 | 260 | def main(): 261 | return SensorApp() 262 | -------------------------------------------------------------------------------- /src/sensorapp/resources/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StoneSteel27/SensorApp/62d861258813f3f54ea8329bd8726e298f2a7b6b/src/sensorapp/resources/__init__.py -------------------------------------------------------------------------------- /src/sensorapp/resources/sensorapp.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StoneSteel27/SensorApp/62d861258813f3f54ea8329bd8726e298f2a7b6b/src/sensorapp/resources/sensorapp.icns -------------------------------------------------------------------------------- /src/sensorapp/resources/sensorapp.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StoneSteel27/SensorApp/62d861258813f3f54ea8329bd8726e298f2a7b6b/src/sensorapp/resources/sensorapp.ico -------------------------------------------------------------------------------- /src/sensorapp/resources/sensorapp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StoneSteel27/SensorApp/62d861258813f3f54ea8329bd8726e298f2a7b6b/src/sensorapp/resources/sensorapp.png -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StoneSteel27/SensorApp/62d861258813f3f54ea8329bd8726e298f2a7b6b/tests/__init__.py -------------------------------------------------------------------------------- /tests/sensorapp.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | import tempfile 4 | from pathlib import Path 5 | 6 | import pytest 7 | 8 | 9 | def run_tests(): 10 | project_path = Path(__file__).parent.parent 11 | os.chdir(project_path) 12 | 13 | # Determine any args to pass to pytest. If there aren't any, 14 | # default to running the whole test suite. 15 | args = sys.argv[1:] 16 | if len(args) == 0: 17 | args = ["tests"] 18 | 19 | returncode = pytest.main( 20 | [ 21 | # Turn up verbosity 22 | "-vv", 23 | # Disable color 24 | "--color=no", 25 | # Overwrite the cache directory to somewhere writable 26 | "-o", 27 | f"cache_dir={tempfile.gettempdir()}/.pytest_cache", 28 | ] + args 29 | ) 30 | 31 | print(f">>>>>>>>>> EXIT {returncode} <<<<<<<<<<") 32 | 33 | 34 | if __name__ == "__main__": 35 | run_tests() 36 | -------------------------------------------------------------------------------- /tests/test_app.py: -------------------------------------------------------------------------------- 1 | def test_first(): 2 | """An initial test for the app.""" 3 | assert 1 + 1 == 2 4 | --------------------------------------------------------------------------------