mirror of
https://github.com/cagnulein/qdomyos-zwift.git
synced 2026-02-18 00:17:41 +01:00
Compare commits
9 Commits
build-1197
...
virtualgea
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3a250fe3a3 | ||
|
|
094d2c88cb | ||
|
|
7f3dda70fd | ||
|
|
79d96ba182 | ||
|
|
5ec861dab3 | ||
|
|
f90edbd632 | ||
|
|
621ed69627 | ||
|
|
b754b7f773 | ||
|
|
efb9dfbdb1 |
@@ -371,4 +371,5 @@ The ProForm 995i implementation serves as the reference example:
|
||||
## Additional Memories
|
||||
|
||||
- When adding a new setting in QML (setting-tiles.qml), you must:
|
||||
* Add the property at the END of the properties list
|
||||
* Add the property at the END of the properties list
|
||||
- #usa le qdebug invece che le emit debug
|
||||
@@ -106,6 +106,16 @@
|
||||
android:name=".ScreenCaptureService"
|
||||
android:foregroundServiceType="mediaProjection" />
|
||||
|
||||
<service android:name=".VirtualGearingService"
|
||||
android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.accessibilityservice.AccessibilityService" />
|
||||
</intent-filter>
|
||||
<meta-data android:name="android.accessibilityservice"
|
||||
android:resource="@xml/virtual_gearing_service_config" />
|
||||
</service>
|
||||
|
||||
<meta-data
|
||||
android:name="com.google.mlkit.vision.DEPENDENCIES"
|
||||
android:value="ocr" />
|
||||
|
||||
4
src/android/res/values/strings.xml
Normal file
4
src/android/res/values/strings.xml
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="virtual_gearing_service_description">Virtual Gearing Service for QZ - Enables touch simulation for virtual shifting in cycling apps</string>
|
||||
</resources>
|
||||
10
src/android/res/xml/virtual_gearing_service_config.xml
Normal file
10
src/android/res/xml/virtual_gearing_service_config.xml
Normal file
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:description="@string/virtual_gearing_service_description"
|
||||
android:packageNames="@null"
|
||||
android:accessibilityEventTypes="typeAllMask"
|
||||
android:accessibilityFlags="flagDefault"
|
||||
android:accessibilityFeedbackType="feedbackGeneric"
|
||||
android:notificationTimeout="100"
|
||||
android:canRetrieveWindowContent="true"
|
||||
android:canPerformGestures="true" />
|
||||
116
src/android/src/AppConfiguration.java
Normal file
116
src/android/src/AppConfiguration.java
Normal file
@@ -0,0 +1,116 @@
|
||||
package org.cagnulen.qdomyoszwift;
|
||||
|
||||
import org.cagnulen.qdomyoszwift.QLog;
|
||||
|
||||
public class AppConfiguration {
|
||||
private static final String TAG = "AppConfiguration";
|
||||
|
||||
public static class TouchCoordinate {
|
||||
public final double xPercent;
|
||||
public final double yPercent;
|
||||
|
||||
public TouchCoordinate(double xPercent, double yPercent) {
|
||||
this.xPercent = xPercent;
|
||||
this.yPercent = yPercent;
|
||||
}
|
||||
|
||||
public int getX(int screenWidth) {
|
||||
return (int) (screenWidth * xPercent);
|
||||
}
|
||||
|
||||
public int getY(int screenHeight) {
|
||||
return (int) (screenHeight * yPercent);
|
||||
}
|
||||
}
|
||||
|
||||
public static class AppConfig {
|
||||
public final String appName;
|
||||
public final String packageName;
|
||||
public final TouchCoordinate shiftUp;
|
||||
public final TouchCoordinate shiftDown;
|
||||
|
||||
public AppConfig(String appName, String packageName, TouchCoordinate shiftUp, TouchCoordinate shiftDown) {
|
||||
this.appName = appName;
|
||||
this.packageName = packageName;
|
||||
this.shiftUp = shiftUp;
|
||||
this.shiftDown = shiftDown;
|
||||
}
|
||||
}
|
||||
|
||||
// Predefined configurations based on SwiftControl
|
||||
private static final AppConfig[] SUPPORTED_APPS = {
|
||||
// MyWhoosh - coordinates from SwiftControl repository
|
||||
new AppConfig(
|
||||
"MyWhoosh",
|
||||
"com.mywhoosh.whooshgame",
|
||||
new TouchCoordinate(0.98, 0.94), // Shift Up - bottom right corner
|
||||
new TouchCoordinate(0.80, 0.94) // Shift Down - more to the left
|
||||
),
|
||||
|
||||
// IndieVelo / TrainingPeaks
|
||||
new AppConfig(
|
||||
"IndieVelo",
|
||||
"com.indieVelo.client",
|
||||
new TouchCoordinate(0.66, 0.74), // Shift Up - center right
|
||||
new TouchCoordinate(0.575, 0.74) // Shift Down - center left
|
||||
),
|
||||
|
||||
// Biketerra.com
|
||||
new AppConfig(
|
||||
"Biketerra",
|
||||
"biketerra",
|
||||
new TouchCoordinate(0.8, 0.5), // Generic coordinates for now
|
||||
new TouchCoordinate(0.2, 0.5)
|
||||
),
|
||||
|
||||
// Default configuration for unrecognized apps
|
||||
new AppConfig(
|
||||
"Default",
|
||||
"*",
|
||||
new TouchCoordinate(0.85, 0.9), // Conservative coordinates
|
||||
new TouchCoordinate(0.15, 0.9)
|
||||
)
|
||||
};
|
||||
|
||||
public static AppConfig getConfigForPackage(String packageName) {
|
||||
// Use custom coordinates from settings instead of hardcoded values
|
||||
return getCurrentConfig();
|
||||
}
|
||||
|
||||
// Get current configuration from user settings
|
||||
public static AppConfig getCurrentConfig() {
|
||||
try {
|
||||
double shiftUpX = VirtualGearingBridge.getVirtualGearingShiftUpX();
|
||||
double shiftUpY = VirtualGearingBridge.getVirtualGearingShiftUpY();
|
||||
double shiftDownX = VirtualGearingBridge.getVirtualGearingShiftDownX();
|
||||
double shiftDownY = VirtualGearingBridge.getVirtualGearingShiftDownY();
|
||||
int appIndex = VirtualGearingBridge.getVirtualGearingApp();
|
||||
|
||||
String appName = "Custom";
|
||||
if (appIndex >= 0 && appIndex < SUPPORTED_APPS.length) {
|
||||
appName = SUPPORTED_APPS[appIndex].appName;
|
||||
}
|
||||
|
||||
QLog.d(TAG, "Using custom coordinates: shiftUp(" + shiftUpX + "," + shiftUpY +
|
||||
") shiftDown(" + shiftDownX + "," + shiftDownY + ") for " + appName);
|
||||
|
||||
return new AppConfig(
|
||||
appName,
|
||||
"*", // Package name not relevant for custom config
|
||||
new TouchCoordinate(shiftUpX, shiftUpY),
|
||||
new TouchCoordinate(shiftDownX, shiftDownY)
|
||||
);
|
||||
} catch (Exception e) {
|
||||
QLog.e(TAG, "Error getting custom config, using fallback", e);
|
||||
return getDefaultConfig();
|
||||
}
|
||||
}
|
||||
|
||||
public static AppConfig getDefaultConfig() {
|
||||
return SUPPORTED_APPS[SUPPORTED_APPS.length - 1]; // Last element is the default
|
||||
}
|
||||
|
||||
public static AppConfig[] getAllConfigs() {
|
||||
return SUPPORTED_APPS;
|
||||
}
|
||||
}
|
||||
145
src/android/src/VirtualGearingBridge.java
Normal file
145
src/android/src/VirtualGearingBridge.java
Normal file
@@ -0,0 +1,145 @@
|
||||
package org.cagnulen.qdomyoszwift;
|
||||
|
||||
import android.app.ActivityManager;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.provider.Settings;
|
||||
import android.text.TextUtils;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.view.WindowManager;
|
||||
import org.cagnulen.qdomyoszwift.QLog;
|
||||
|
||||
public class VirtualGearingBridge {
|
||||
private static final String TAG = "VirtualGearingBridge";
|
||||
|
||||
public static boolean isAccessibilityServiceEnabled(Context context) {
|
||||
String settingValue = Settings.Secure.getString(
|
||||
context.getContentResolver(),
|
||||
Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);
|
||||
|
||||
QLog.d(TAG, "Enabled accessibility services: " + settingValue);
|
||||
|
||||
if (settingValue != null) {
|
||||
TextUtils.SimpleStringSplitter splitter = new TextUtils.SimpleStringSplitter(':');
|
||||
splitter.setString(settingValue);
|
||||
while (splitter.hasNext()) {
|
||||
String service = splitter.next();
|
||||
QLog.d(TAG, "Checking service: " + service);
|
||||
if (service.contains("org.cagnulen.qdomyoszwift/.VirtualGearingService") ||
|
||||
service.contains("VirtualGearingService")) {
|
||||
QLog.d(TAG, "VirtualGearingService is enabled");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
QLog.d(TAG, "VirtualGearingService is not enabled");
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void openAccessibilitySettings(Context context) {
|
||||
try {
|
||||
Intent intent = new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS);
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
context.startActivity(intent);
|
||||
QLog.d(TAG, "Opened accessibility settings");
|
||||
} catch (Exception e) {
|
||||
QLog.e(TAG, "Failed to open accessibility settings", e);
|
||||
}
|
||||
}
|
||||
|
||||
public static void simulateShiftUp() {
|
||||
QLog.d(TAG, "Simulating shift up with app-specific coordinates");
|
||||
VirtualGearingService.shiftUpSmart();
|
||||
}
|
||||
|
||||
public static void simulateShiftDown() {
|
||||
QLog.d(TAG, "Simulating shift down with app-specific coordinates");
|
||||
VirtualGearingService.shiftDownSmart();
|
||||
}
|
||||
|
||||
public static String getCurrentAppPackageName(Context context) {
|
||||
try {
|
||||
ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
|
||||
if (activityManager != null) {
|
||||
ActivityManager.RunningAppProcessInfo myProcess = new ActivityManager.RunningAppProcessInfo();
|
||||
ActivityManager.getMyMemoryState(myProcess);
|
||||
|
||||
// For Android 5.0+ we should use UsageStatsManager, but for simplicity
|
||||
// we use a more direct approach via current foreground process
|
||||
// In a complete implementation we should use UsageStatsManager
|
||||
|
||||
// For now return null and let the service detect the app
|
||||
return null;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
QLog.e(TAG, "Error getting current app package name", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static int[] getScreenSize(Context context) {
|
||||
try {
|
||||
WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
|
||||
DisplayMetrics displayMetrics = new DisplayMetrics();
|
||||
windowManager.getDefaultDisplay().getMetrics(displayMetrics);
|
||||
return new int[]{displayMetrics.widthPixels, displayMetrics.heightPixels};
|
||||
} catch (Exception e) {
|
||||
QLog.e(TAG, "Error getting screen size", e);
|
||||
return new int[]{1080, 1920}; // Default fallback
|
||||
}
|
||||
}
|
||||
|
||||
public static void simulateTouch(int x, int y) {
|
||||
QLog.d(TAG, "Simulating touch at (" + x + ", " + y + ")");
|
||||
VirtualGearingService.simulateKeypress(x, y);
|
||||
}
|
||||
|
||||
public static boolean isServiceRunning() {
|
||||
boolean running = VirtualGearingService.isServiceEnabled();
|
||||
QLog.d(TAG, "Service running: " + running);
|
||||
return running;
|
||||
}
|
||||
|
||||
// Native methods to get settings from C++ side
|
||||
public static native double getVirtualGearingShiftUpX();
|
||||
public static native double getVirtualGearingShiftUpY();
|
||||
public static native double getVirtualGearingShiftDownX();
|
||||
public static native double getVirtualGearingShiftDownY();
|
||||
public static native int getVirtualGearingApp();
|
||||
|
||||
// Methods to get coordinates that will be/were sent
|
||||
public static String getShiftUpCoordinates() {
|
||||
try {
|
||||
AppConfiguration.AppConfig config = AppConfiguration.getCurrentConfig();
|
||||
// Use VirtualGearingService to get screen size (it has access to service context)
|
||||
int[] screenSize = VirtualGearingService.getScreenSize();
|
||||
int x = config.shiftUp.getX(screenSize[0]);
|
||||
int y = config.shiftUp.getY(screenSize[1]);
|
||||
return x + "," + y;
|
||||
} catch (Exception e) {
|
||||
QLog.e(TAG, "Error getting shift up coordinates", e);
|
||||
return "0,0";
|
||||
}
|
||||
}
|
||||
|
||||
public static String getShiftDownCoordinates() {
|
||||
try {
|
||||
AppConfiguration.AppConfig config = AppConfiguration.getCurrentConfig();
|
||||
// Use VirtualGearingService to get screen size (it has access to service context)
|
||||
int[] screenSize = VirtualGearingService.getScreenSize();
|
||||
int x = config.shiftDown.getX(screenSize[0]);
|
||||
int y = config.shiftDown.getY(screenSize[1]);
|
||||
return x + "," + y;
|
||||
} catch (Exception e) {
|
||||
QLog.e(TAG, "Error getting shift down coordinates", e);
|
||||
return "0,0";
|
||||
}
|
||||
}
|
||||
|
||||
public static String getLastTouchCoordinates() {
|
||||
// For now, return the last coordinates that would be sent for shift up
|
||||
// This could be enhanced to track actual last touch
|
||||
return getShiftUpCoordinates();
|
||||
}
|
||||
}
|
||||
152
src/android/src/VirtualGearingService.java
Normal file
152
src/android/src/VirtualGearingService.java
Normal file
@@ -0,0 +1,152 @@
|
||||
package org.cagnulen.qdomyoszwift;
|
||||
|
||||
import android.accessibilityservice.AccessibilityService;
|
||||
import android.accessibilityservice.GestureDescription;
|
||||
import android.graphics.Path;
|
||||
import android.view.ViewConfiguration;
|
||||
import android.view.accessibility.AccessibilityEvent;
|
||||
import org.cagnulen.qdomyoszwift.QLog;
|
||||
|
||||
public class VirtualGearingService extends AccessibilityService {
|
||||
private static final String TAG = "VirtualGearingService";
|
||||
private static VirtualGearingService instance;
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
instance = this;
|
||||
QLog.d(TAG, "VirtualGearingService created");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
instance = null;
|
||||
QLog.d(TAG, "VirtualGearingService destroyed");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAccessibilityEvent(AccessibilityEvent event) {
|
||||
// Capture foreground app package name for smart coordinates
|
||||
if (event != null && event.getPackageName() != null) {
|
||||
String packageName = event.getPackageName().toString();
|
||||
if (!packageName.equals(currentPackageName)) {
|
||||
currentPackageName = packageName;
|
||||
QLog.d(TAG, "App changed to: " + packageName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onInterrupt() {
|
||||
QLog.d(TAG, "VirtualGearingService interrupted");
|
||||
}
|
||||
|
||||
public static boolean isServiceEnabled() {
|
||||
return instance != null;
|
||||
}
|
||||
|
||||
public static void simulateKeypress(int x, int y) {
|
||||
if (instance == null) {
|
||||
QLog.w(TAG, "Service not enabled, cannot simulate keypress");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
GestureDescription.Builder gestureBuilder = new GestureDescription.Builder();
|
||||
Path path = new Path();
|
||||
path.moveTo(x, y);
|
||||
path.lineTo(x + 1, y);
|
||||
|
||||
GestureDescription.StrokeDescription stroke = new GestureDescription.StrokeDescription(
|
||||
path, 0, ViewConfiguration.getTapTimeout(), false);
|
||||
gestureBuilder.addStroke(stroke);
|
||||
|
||||
instance.dispatchGesture(gestureBuilder.build(), null, null);
|
||||
QLog.d(TAG, "Simulated keypress at (" + x + ", " + y + ")");
|
||||
} catch (Exception e) {
|
||||
QLog.e(TAG, "Error simulating keypress", e);
|
||||
}
|
||||
}
|
||||
|
||||
// Legacy methods for backward compatibility
|
||||
public static void shiftUp() {
|
||||
QLog.d(TAG, "Using legacy shiftUp - consider using shiftUpSmart()");
|
||||
simulateKeypress(100, 200);
|
||||
}
|
||||
|
||||
public static void shiftDown() {
|
||||
QLog.d(TAG, "Using legacy shiftDown - consider using shiftDownSmart()");
|
||||
simulateKeypress(100, 300);
|
||||
}
|
||||
|
||||
// New smart methods with app-specific coordinates
|
||||
public static void shiftUpSmart() {
|
||||
if (instance == null) {
|
||||
QLog.w(TAG, "Service not enabled, cannot simulate smart shift up");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// Try to detect app from package name of last AccessibilityEvent
|
||||
String currentPackage = getCurrentPackageName();
|
||||
AppConfiguration.AppConfig config = AppConfiguration.getConfigForPackage(currentPackage);
|
||||
|
||||
// Calculate coordinates based on screen dimensions
|
||||
int[] screenSize = getScreenSize();
|
||||
int x = config.shiftUp.getX(screenSize[0]);
|
||||
int y = config.shiftUp.getY(screenSize[1]);
|
||||
|
||||
QLog.d(TAG, "Smart shift up for " + config.appName + " at (" + x + ", " + y + ")");
|
||||
simulateKeypress(x, y);
|
||||
} catch (Exception e) {
|
||||
QLog.e(TAG, "Error in shiftUpSmart, falling back to legacy", e);
|
||||
shiftUp();
|
||||
}
|
||||
}
|
||||
|
||||
public static void shiftDownSmart() {
|
||||
if (instance == null) {
|
||||
QLog.w(TAG, "Service not enabled, cannot simulate smart shift down");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
String currentPackage = getCurrentPackageName();
|
||||
AppConfiguration.AppConfig config = AppConfiguration.getConfigForPackage(currentPackage);
|
||||
|
||||
int[] screenSize = getScreenSize();
|
||||
int x = config.shiftDown.getX(screenSize[0]);
|
||||
int y = config.shiftDown.getY(screenSize[1]);
|
||||
|
||||
QLog.d(TAG, "Smart shift down for " + config.appName + " at (" + x + ", " + y + ")");
|
||||
simulateKeypress(x, y);
|
||||
} catch (Exception e) {
|
||||
QLog.e(TAG, "Error in shiftDownSmart, falling back to legacy", e);
|
||||
shiftDown();
|
||||
}
|
||||
}
|
||||
|
||||
private static String currentPackageName = null;
|
||||
|
||||
private static String getCurrentPackageName() {
|
||||
return currentPackageName != null ? currentPackageName : "unknown";
|
||||
}
|
||||
|
||||
public static int[] getScreenSize() {
|
||||
if (instance != null) {
|
||||
try {
|
||||
android.content.res.Resources resources = instance.getResources();
|
||||
android.util.DisplayMetrics displayMetrics = resources.getDisplayMetrics();
|
||||
int width = displayMetrics.widthPixels;
|
||||
int height = displayMetrics.heightPixels;
|
||||
QLog.d(TAG, "Screen size: " + width + "x" + height + " (density=" + displayMetrics.density + ")");
|
||||
return new int[]{width, height};
|
||||
} catch (Exception e) {
|
||||
QLog.e(TAG, "Error getting screen size from service", e);
|
||||
}
|
||||
}
|
||||
QLog.w(TAG, "Using fallback screen size");
|
||||
return new int[]{1080, 1920}; // Default fallback
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
#include "devices/bike.h"
|
||||
#include "qdebugfixup.h"
|
||||
#include "homeform.h"
|
||||
#include "virtualgearingdevice.h"
|
||||
#include <QSettings>
|
||||
|
||||
bike::bike() { elapsed.setType(metric::METRIC_ELAPSED); }
|
||||
@@ -466,7 +467,81 @@ double bike::gearsZwiftRatio() {
|
||||
case 23:
|
||||
return 5.14;
|
||||
case 24:
|
||||
return 5.49;
|
||||
return 5.49;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void bike::gearUp() {
|
||||
QSettings settings;
|
||||
|
||||
// Check if virtual gearing device is enabled
|
||||
if (settings.value(QZSettings::virtual_gearing_device, QZSettings::default_virtual_gearing_device).toBool()) {
|
||||
#ifdef Q_OS_ANDROID
|
||||
VirtualGearingDevice* vgd = VirtualGearingDevice::instance();
|
||||
if (vgd) {
|
||||
// Check if accessibility service is enabled
|
||||
if (!vgd->isAccessibilityServiceEnabled()) {
|
||||
static bool warned = false;
|
||||
if (!warned) {
|
||||
qDebug() << "bike::gearUp() - VirtualGearingService not enabled in accessibility settings";
|
||||
qDebug() << "Please enable the Virtual Gearing Service in Android Accessibility Settings";
|
||||
warned = true;
|
||||
}
|
||||
} else if (vgd->isServiceRunning()) {
|
||||
qDebug() << "bike::gearUp() - Using virtual gearing device";
|
||||
QString coordinates = vgd->getShiftUpCoordinates();
|
||||
vgd->simulateShiftUp();
|
||||
|
||||
// Show toast with coordinates
|
||||
homeform::singleton()->setToastRequested("Virtual Gear Up → " + coordinates);
|
||||
return;
|
||||
} else {
|
||||
qDebug() << "bike::gearUp() - Virtual gearing service not running, falling back to normal gearing";
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// Normal gearing logic
|
||||
bool gears_zwift_ratio = settings.value(QZSettings::gears_zwift_ratio, QZSettings::default_gears_zwift_ratio).toBool();
|
||||
setGears(gears() + (gears_zwift_ratio ? 1 :
|
||||
settings.value(QZSettings::gears_gain, QZSettings::default_gears_gain).toDouble()));
|
||||
}
|
||||
|
||||
void bike::gearDown() {
|
||||
QSettings settings;
|
||||
|
||||
// Check if virtual gearing device is enabled
|
||||
if (settings.value(QZSettings::virtual_gearing_device, QZSettings::default_virtual_gearing_device).toBool()) {
|
||||
#ifdef Q_OS_ANDROID
|
||||
VirtualGearingDevice* vgd = VirtualGearingDevice::instance();
|
||||
if (vgd) {
|
||||
// Check if accessibility service is enabled
|
||||
if (!vgd->isAccessibilityServiceEnabled()) {
|
||||
static bool warned = false;
|
||||
if (!warned) {
|
||||
qDebug() << "bike::gearDown() - VirtualGearingService not enabled in accessibility settings";
|
||||
qDebug() << "Please enable the Virtual Gearing Service in Android Accessibility Settings";
|
||||
warned = true;
|
||||
}
|
||||
} else if (vgd->isServiceRunning()) {
|
||||
qDebug() << "bike::gearDown() - Using virtual gearing device";
|
||||
QString coordinates = vgd->getShiftDownCoordinates();
|
||||
vgd->simulateShiftDown();
|
||||
|
||||
// Show toast with coordinates
|
||||
homeform::singleton()->setToastRequested("Virtual Gear Down → " + coordinates);
|
||||
return;
|
||||
} else {
|
||||
qDebug() << "bike::gearDown() - Virtual gearing service not running, falling back to normal gearing";
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// Normal gearing logic
|
||||
bool gears_zwift_ratio = settings.value(QZSettings::gears_zwift_ratio, QZSettings::default_gears_zwift_ratio).toBool();
|
||||
setGears(gears() - (gears_zwift_ratio ? 1 :
|
||||
settings.value(QZSettings::gears_gain, QZSettings::default_gears_gain).toDouble()));
|
||||
}
|
||||
|
||||
@@ -64,18 +64,8 @@ class bike : public bluetoothdevice {
|
||||
void changeInclination(double grade, double percentage) override;
|
||||
virtual void changeSteeringAngle(double angle) { m_steeringAngle = angle; }
|
||||
virtual void resistanceFromFTMSAccessory(resistance_t res) { Q_UNUSED(res); }
|
||||
void gearUp() {
|
||||
QSettings settings;
|
||||
bool gears_zwift_ratio = settings.value(QZSettings::gears_zwift_ratio, QZSettings::default_gears_zwift_ratio).toBool();
|
||||
setGears(gears() + (gears_zwift_ratio ? 1 :
|
||||
settings.value(QZSettings::gears_gain, QZSettings::default_gears_gain).toDouble()));
|
||||
}
|
||||
void gearDown() {
|
||||
QSettings settings;
|
||||
bool gears_zwift_ratio = settings.value(QZSettings::gears_zwift_ratio, QZSettings::default_gears_zwift_ratio).toBool();
|
||||
setGears(gears() - (gears_zwift_ratio ? 1 :
|
||||
settings.value(QZSettings::gears_gain, QZSettings::default_gears_gain).toDouble()));
|
||||
}
|
||||
void gearUp();
|
||||
void gearDown();
|
||||
|
||||
Q_SIGNALS:
|
||||
void bikeStarted();
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include "mqttpublisher.h"
|
||||
#include "androidstatusbar.h"
|
||||
#include "fontmanager.h"
|
||||
#include "virtualgearingdevice.h"
|
||||
|
||||
#ifdef Q_OS_ANDROID
|
||||
#include "keepawakehelper.h"
|
||||
@@ -782,6 +783,12 @@ int main(int argc, char *argv[]) {
|
||||
bikeResistanceOffset,
|
||||
bikeResistanceGain); // FIXED: clang-analyzer-cplusplus.NewDeleteLeaks - potential leak
|
||||
|
||||
#ifdef Q_OS_ANDROID
|
||||
// Initialize VirtualGearingDevice for Android keypress simulation
|
||||
VirtualGearingDevice* vgd = new VirtualGearingDevice();
|
||||
Q_UNUSED(vgd)
|
||||
#endif
|
||||
|
||||
QString mqtt_host = settings.value(QZSettings::mqtt_host, QZSettings::default_mqtt_host).toString();
|
||||
int mqtt_port = settings.value(QZSettings::mqtt_port, QZSettings::default_mqtt_port).toInt();
|
||||
QString mqtt_username = settings.value(QZSettings::mqtt_username, QZSettings::default_mqtt_username).toString();
|
||||
@@ -807,6 +814,7 @@ int main(int argc, char *argv[]) {
|
||||
#endif
|
||||
{
|
||||
AndroidStatusBar::registerQmlType();
|
||||
VirtualGearingDevice::registerQmlType();
|
||||
|
||||
#ifdef Q_OS_ANDROID
|
||||
FontManager fontManager;
|
||||
|
||||
@@ -9,6 +9,7 @@ import org.cagnulein.qdomyoszwift 1.0
|
||||
import QtQuick.Window 2.12
|
||||
import Qt.labs.platform 1.1
|
||||
import AndroidStatusBar 1.0
|
||||
import VirtualGearingDevice 1.0
|
||||
|
||||
ApplicationWindow {
|
||||
id: window
|
||||
|
||||
@@ -869,6 +869,7 @@ DISTFILES += \
|
||||
$$PWD/android/libs/ciq-companion-app-sdk-2.0.3.aar \
|
||||
$$PWD/android/libs/zaplibrary-debug.aar \
|
||||
$$PWD/android/res/xml/device_filter.xml \
|
||||
$$PWD/android/src/AppConfiguration.java \
|
||||
$$PWD/android/src/BikeChannelController.java \
|
||||
$$PWD/android/src/BleAdvertiser.java \
|
||||
$$PWD/android/src/CSafeRowerUSBHID.java \
|
||||
@@ -883,6 +884,8 @@ DISTFILES += \
|
||||
$$PWD/android/src/QLog.java \
|
||||
$$PWD/android/src/ScreenCaptureService.java \
|
||||
$$PWD/android/src/Shortcuts.java \
|
||||
$$PWD/android/src/VirtualGearingBridge.java \
|
||||
$$PWD/android/src/VirtualGearingService.java \
|
||||
$$PWD/android/src/WearableController.java \
|
||||
$$PWD/android/src/WearableMessageListenerService.java \
|
||||
$$PWD/android/src/ZapClickLayer.java \
|
||||
@@ -981,12 +984,14 @@ ios {
|
||||
HEADERS += \
|
||||
mqttpublisher.h \
|
||||
androidstatusbar.h \
|
||||
fontmanager.h
|
||||
fontmanager.h \
|
||||
virtualgearingdevice.h
|
||||
|
||||
SOURCES += \
|
||||
mqttpublisher.cpp \
|
||||
androidstatusbar.cpp \
|
||||
fontmanager.cpp
|
||||
fontmanager.cpp \
|
||||
virtualgearingdevice.cpp
|
||||
|
||||
include($$PWD/purchasing/purchasing.pri)
|
||||
INCLUDEPATH += purchasing/qmltypes
|
||||
|
||||
@@ -981,11 +981,17 @@ const QString QZSettings::chart_display_mode = QStringLiteral("chart_display_mod
|
||||
const QString QZSettings::calories_active_only = QStringLiteral("calories_active_only");
|
||||
const QString QZSettings::calories_from_hr = QStringLiteral("calories_from_hr");
|
||||
const QString QZSettings::height = QStringLiteral("height");
|
||||
const QString QZSettings::virtual_gearing_device = QStringLiteral("virtual_gearing_device");
|
||||
const QString QZSettings::virtual_gearing_shift_up_x = QStringLiteral("virtual_gearing_shift_up_x");
|
||||
const QString QZSettings::virtual_gearing_shift_up_y = QStringLiteral("virtual_gearing_shift_up_y");
|
||||
const QString QZSettings::virtual_gearing_shift_down_x = QStringLiteral("virtual_gearing_shift_down_x");
|
||||
const QString QZSettings::virtual_gearing_shift_down_y = QStringLiteral("virtual_gearing_shift_down_y");
|
||||
const QString QZSettings::virtual_gearing_app = QStringLiteral("virtual_gearing_app");
|
||||
const QString QZSettings::taurua_ic90 = QStringLiteral("taurua_ic90");
|
||||
const QString QZSettings::proform_csx210 = QStringLiteral("proform_csx210");
|
||||
|
||||
|
||||
const uint32_t allSettingsCount = 807;
|
||||
const uint32_t allSettingsCount = 813;
|
||||
|
||||
QVariant allSettings[allSettingsCount][2] = {
|
||||
{QZSettings::cryptoKeySettingsProfiles, QZSettings::default_cryptoKeySettingsProfiles},
|
||||
@@ -1814,6 +1820,12 @@ QVariant allSettings[allSettingsCount][2] = {
|
||||
{QZSettings::taurua_ic90, QZSettings::default_taurua_ic90},
|
||||
{QZSettings::proform_csx210, QZSettings::default_proform_csx210},
|
||||
{QZSettings::toorxtreadmill_discovery_completed, QZSettings::default_toorxtreadmill_discovery_completed},
|
||||
{QZSettings::virtual_gearing_device, QZSettings::default_virtual_gearing_device},
|
||||
{QZSettings::virtual_gearing_shift_up_x, QZSettings::default_virtual_gearing_shift_up_x},
|
||||
{QZSettings::virtual_gearing_shift_up_y, QZSettings::default_virtual_gearing_shift_up_y},
|
||||
{QZSettings::virtual_gearing_shift_down_x, QZSettings::default_virtual_gearing_shift_down_x},
|
||||
{QZSettings::virtual_gearing_shift_down_y, QZSettings::default_virtual_gearing_shift_down_y},
|
||||
{QZSettings::virtual_gearing_app, QZSettings::default_virtual_gearing_app},
|
||||
};
|
||||
|
||||
void QZSettings::qDebugAllSettings(bool showDefaults) {
|
||||
|
||||
@@ -2693,12 +2693,30 @@ class QZSettings {
|
||||
static const QString height;
|
||||
static constexpr double default_height = 175.0;
|
||||
|
||||
static const QString virtual_gearing_device;
|
||||
static constexpr bool default_virtual_gearing_device = false;
|
||||
|
||||
// Virtual Gearing - Generic coordinate settings (app-agnostic)
|
||||
static const QString virtual_gearing_shift_up_x;
|
||||
static constexpr double default_virtual_gearing_shift_up_x = 0.98;
|
||||
static const QString virtual_gearing_shift_up_y;
|
||||
static constexpr double default_virtual_gearing_shift_up_y = 0.94;
|
||||
static const QString virtual_gearing_shift_down_x;
|
||||
static constexpr double default_virtual_gearing_shift_down_x = 0.80;
|
||||
static const QString virtual_gearing_shift_down_y;
|
||||
static constexpr double default_virtual_gearing_shift_down_y = 0.94;
|
||||
|
||||
// Virtual Gearing - App selection
|
||||
static const QString virtual_gearing_app;
|
||||
static constexpr int default_virtual_gearing_app = 0; // 0=MyWhoosh default
|
||||
|
||||
static const QString taurua_ic90;
|
||||
static constexpr bool default_taurua_ic90 = false;
|
||||
|
||||
static const QString proform_csx210;
|
||||
static constexpr bool default_proform_csx210 = false;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Write the QSettings values using the constants from this namespace.
|
||||
* @param showDefaults Optionally indicates if the default should be shown with the key.
|
||||
|
||||
146
src/settings.qml
146
src/settings.qml
@@ -5,6 +5,7 @@ import QtQuick.Controls.Material 2.0
|
||||
import Qt.labs.settings 1.0
|
||||
import QtQuick.Dialogs 1.0
|
||||
import Qt.labs.platform 1.1
|
||||
import VirtualGearingDevice 1.0
|
||||
|
||||
//Page {
|
||||
ScrollView {
|
||||
@@ -1207,6 +1208,12 @@ import Qt.labs.platform 1.1
|
||||
property bool toorxtreadmill_discovery_completed: false
|
||||
property bool taurua_ic90: false
|
||||
property bool proform_csx210: false
|
||||
property bool virtual_gearing_device: false
|
||||
property double virtual_gearing_shift_up_x: 0.98
|
||||
property double virtual_gearing_shift_up_y: 0.94
|
||||
property double virtual_gearing_shift_down_x: 0.80
|
||||
property double virtual_gearing_shift_down_y: 0.94
|
||||
property int virtual_gearing_app: 0
|
||||
}
|
||||
|
||||
|
||||
@@ -12878,6 +12885,145 @@ import Qt.labs.platform 1.1
|
||||
color: Material.color(Material.Lime)
|
||||
}
|
||||
|
||||
IndicatorOnlySwitch {
|
||||
id: virtualGearingDeviceDelegate
|
||||
text: qsTr("Virtual Gearing Device")
|
||||
spacing: 0
|
||||
bottomPadding: 0
|
||||
topPadding: 0
|
||||
rightPadding: 0
|
||||
leftPadding: 0
|
||||
clip: false
|
||||
checked: settings.virtual_gearing_device
|
||||
Layout.alignment: Qt.AlignLeft | Qt.AlignTop
|
||||
Layout.fillWidth: true
|
||||
visible: Qt.platform.os === "android"
|
||||
onClicked: {
|
||||
settings.virtual_gearing_device = checked;
|
||||
if (checked) {
|
||||
// Auto-enable Android notification and fake bike when virtual gearing is enabled
|
||||
settings.android_notification = true;
|
||||
settings.virtual_device_enabled = true;
|
||||
}
|
||||
window.settings_restart_to_apply = true;
|
||||
}
|
||||
}
|
||||
|
||||
Label {
|
||||
text: qsTr("Android Only: enables virtual gearing through keypress simulation for third-party apps like MyWhoosh and indieVelo. Uses Zwift Play/Click controls to send shift commands.")
|
||||
font.bold: true
|
||||
font.italic: true
|
||||
font.pixelSize: Qt.application.font.pixelSize - 2
|
||||
textFormat: Text.PlainText
|
||||
wrapMode: Text.WordWrap
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
Layout.alignment: Qt.AlignLeft | Qt.AlignTop
|
||||
Layout.fillWidth: true
|
||||
color: Material.color(Material.Lime)
|
||||
visible: Qt.platform.os === "android"
|
||||
}
|
||||
|
||||
Button {
|
||||
text: qsTr("Open Accessibility Settings")
|
||||
Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter
|
||||
visible: settings.virtual_gearing_device && Qt.platform.os === "android"
|
||||
onClicked: {
|
||||
VirtualGearingDevice.openAccessibilitySettings()
|
||||
}
|
||||
}
|
||||
|
||||
// App Selection ComboBox
|
||||
Row {
|
||||
visible: settings.virtual_gearing_device && Qt.platform.os === "android"
|
||||
Layout.fillWidth: true
|
||||
spacing: 10
|
||||
|
||||
Label {
|
||||
text: qsTr("Target App:")
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
ComboBox {
|
||||
id: virtualGearingAppCombo
|
||||
model: ["MyWhoosh", "IndieVelo", "Biketerra", "RGT Cycling", "Zwift"]
|
||||
currentIndex: settings.virtual_gearing_app
|
||||
onCurrentIndexChanged: {
|
||||
settings.virtual_gearing_app = currentIndex;
|
||||
// Auto-populate coordinates based on selected app
|
||||
if (currentIndex === 0) { // MyWhoosh
|
||||
settings.virtual_gearing_shift_up_x = 0.98;
|
||||
settings.virtual_gearing_shift_up_y = 0.94;
|
||||
settings.virtual_gearing_shift_down_x = 0.80;
|
||||
settings.virtual_gearing_shift_down_y = 0.94;
|
||||
} else if (currentIndex === 1) { // IndieVelo
|
||||
settings.virtual_gearing_shift_up_x = 0.66;
|
||||
settings.virtual_gearing_shift_up_y = 0.74;
|
||||
settings.virtual_gearing_shift_down_x = 0.575;
|
||||
settings.virtual_gearing_shift_down_y = 0.74;
|
||||
} else if (currentIndex === 2) { // Biketerra
|
||||
settings.virtual_gearing_shift_up_x = 0.8;
|
||||
settings.virtual_gearing_shift_up_y = 0.5;
|
||||
settings.virtual_gearing_shift_down_x = 0.2;
|
||||
settings.virtual_gearing_shift_down_y = 0.5;
|
||||
} else { // RGT Cycling, Zwift and others
|
||||
settings.virtual_gearing_shift_up_x = 0.95;
|
||||
settings.virtual_gearing_shift_up_y = 0.85;
|
||||
settings.virtual_gearing_shift_down_x = 0.75;
|
||||
settings.virtual_gearing_shift_down_y = 0.85;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Coordinate Customization
|
||||
GridLayout {
|
||||
visible: settings.virtual_gearing_device && Qt.platform.os === "android"
|
||||
Layout.fillWidth: true
|
||||
columns: 4
|
||||
|
||||
Label { text: qsTr("Shift Up X:") }
|
||||
TextField {
|
||||
text: settings.virtual_gearing_shift_up_x.toFixed(3)
|
||||
onAccepted: settings.virtual_gearing_shift_up_x = parseFloat(text)
|
||||
validator: DoubleValidator { bottom: 0.0; top: 1.0; decimals: 3 }
|
||||
}
|
||||
|
||||
Label { text: qsTr("Shift Up Y:") }
|
||||
TextField {
|
||||
text: settings.virtual_gearing_shift_up_y.toFixed(3)
|
||||
onAccepted: settings.virtual_gearing_shift_up_y = parseFloat(text)
|
||||
validator: DoubleValidator { bottom: 0.0; top: 1.0; decimals: 3 }
|
||||
}
|
||||
|
||||
Label { text: qsTr("Shift Down X:") }
|
||||
TextField {
|
||||
text: settings.virtual_gearing_shift_down_x.toFixed(3)
|
||||
onAccepted: settings.virtual_gearing_shift_down_x = parseFloat(text)
|
||||
validator: DoubleValidator { bottom: 0.0; top: 1.0; decimals: 3 }
|
||||
}
|
||||
|
||||
Label { text: qsTr("Shift Down Y:") }
|
||||
TextField {
|
||||
text: settings.virtual_gearing_shift_down_y.toFixed(3)
|
||||
onAccepted: settings.virtual_gearing_shift_down_y = parseFloat(text)
|
||||
validator: DoubleValidator { bottom: 0.0; top: 1.0; decimals: 3 }
|
||||
}
|
||||
}
|
||||
|
||||
Label {
|
||||
visible: settings.virtual_gearing_device && Qt.platform.os === "android"
|
||||
text: qsTr("Coordinates are percentages (0.0-1.0) of screen dimensions. Select an app above to auto-populate with default values, then customize as needed.")
|
||||
font.bold: true
|
||||
font.italic: true
|
||||
font.pixelSize: Qt.application.font.pixelSize - 2
|
||||
textFormat: Text.PlainText
|
||||
wrapMode: Text.WordWrap
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
Layout.alignment: Qt.AlignLeft | Qt.AlignTop
|
||||
Layout.fillWidth: true
|
||||
color: Material.color(Material.Lime)
|
||||
}
|
||||
|
||||
IndicatorOnlySwitch {
|
||||
text: qsTr("Android Force Documents/QZ Folder")
|
||||
spacing: 0
|
||||
|
||||
202
src/virtualgearingdevice.cpp
Normal file
202
src/virtualgearingdevice.cpp
Normal file
@@ -0,0 +1,202 @@
|
||||
#include "virtualgearingdevice.h"
|
||||
#include "qzsettings.h"
|
||||
#include <QDebug>
|
||||
#include <QQmlEngine>
|
||||
#include <QSettings>
|
||||
|
||||
#ifdef Q_OS_ANDROID
|
||||
#include <QtAndroid>
|
||||
#include <QAndroidJniEnvironment>
|
||||
#include <QAndroidJniObject>
|
||||
#include <jni.h>
|
||||
#endif
|
||||
|
||||
VirtualGearingDevice* VirtualGearingDevice::m_instance = nullptr;
|
||||
|
||||
VirtualGearingDevice::VirtualGearingDevice(QObject *parent) : QObject(parent)
|
||||
{
|
||||
m_instance = this;
|
||||
}
|
||||
|
||||
VirtualGearingDevice* VirtualGearingDevice::instance()
|
||||
{
|
||||
return m_instance;
|
||||
}
|
||||
|
||||
void VirtualGearingDevice::registerQmlType()
|
||||
{
|
||||
qmlRegisterSingletonType<VirtualGearingDevice>("VirtualGearingDevice", 1, 0, "VirtualGearingDevice",
|
||||
[](QQmlEngine *engine, QJSEngine *scriptEngine) -> QObject* {
|
||||
Q_UNUSED(engine)
|
||||
Q_UNUSED(scriptEngine)
|
||||
return instance();
|
||||
});
|
||||
}
|
||||
|
||||
bool VirtualGearingDevice::isAccessibilityServiceEnabled()
|
||||
{
|
||||
#ifdef Q_OS_ANDROID
|
||||
QAndroidJniObject activity = QtAndroid::androidActivity();
|
||||
if (activity.isValid()) {
|
||||
return QAndroidJniObject::callStaticMethod<jboolean>(
|
||||
"org/cagnulen/qdomyoszwift/VirtualGearingBridge",
|
||||
"isAccessibilityServiceEnabled",
|
||||
"(Landroid/content/Context;)Z",
|
||||
activity.object<jobject>());
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
void VirtualGearingDevice::openAccessibilitySettings()
|
||||
{
|
||||
#ifdef Q_OS_ANDROID
|
||||
QAndroidJniObject activity = QtAndroid::androidActivity();
|
||||
if (activity.isValid()) {
|
||||
QAndroidJniObject::callStaticMethod<void>(
|
||||
"org/cagnulen/qdomyoszwift/VirtualGearingBridge",
|
||||
"openAccessibilitySettings",
|
||||
"(Landroid/content/Context;)V",
|
||||
activity.object<jobject>());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void VirtualGearingDevice::simulateShiftUp()
|
||||
{
|
||||
#ifdef Q_OS_ANDROID
|
||||
qDebug() << "VirtualGearingDevice: Simulating shift up";
|
||||
QAndroidJniObject::callStaticMethod<void>(
|
||||
"org/cagnulen/qdomyoszwift/VirtualGearingBridge",
|
||||
"simulateShiftUp",
|
||||
"()V");
|
||||
#endif
|
||||
}
|
||||
|
||||
void VirtualGearingDevice::simulateShiftDown()
|
||||
{
|
||||
#ifdef Q_OS_ANDROID
|
||||
qDebug() << "VirtualGearingDevice: Simulating shift down";
|
||||
QAndroidJniObject::callStaticMethod<void>(
|
||||
"org/cagnulen/qdomyoszwift/VirtualGearingBridge",
|
||||
"simulateShiftDown",
|
||||
"()V");
|
||||
#endif
|
||||
}
|
||||
|
||||
void VirtualGearingDevice::simulateTouch(int x, int y)
|
||||
{
|
||||
#ifdef Q_OS_ANDROID
|
||||
qDebug() << "VirtualGearingDevice: Simulating touch at (" << x << ", " << y << ")";
|
||||
QAndroidJniObject::callStaticMethod<void>(
|
||||
"org/cagnulen/qdomyoszwift/VirtualGearingBridge",
|
||||
"simulateTouch",
|
||||
"(II)V",
|
||||
x, y);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool VirtualGearingDevice::isServiceRunning()
|
||||
{
|
||||
#ifdef Q_OS_ANDROID
|
||||
return QAndroidJniObject::callStaticMethod<jboolean>(
|
||||
"org/cagnulen/qdomyoszwift/VirtualGearingBridge",
|
||||
"isServiceRunning",
|
||||
"()Z");
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef Q_OS_ANDROID
|
||||
// JNI implementations for settings access
|
||||
extern "C" {
|
||||
|
||||
JNIEXPORT jdouble JNICALL
|
||||
Java_org_cagnulen_qdomyoszwift_VirtualGearingBridge_getVirtualGearingShiftUpX(JNIEnv *env, jclass clazz)
|
||||
{
|
||||
Q_UNUSED(env)
|
||||
Q_UNUSED(clazz)
|
||||
QSettings settings;
|
||||
return settings.value(QZSettings::virtual_gearing_shift_up_x, QZSettings::default_virtual_gearing_shift_up_x).toDouble();
|
||||
}
|
||||
|
||||
JNIEXPORT jdouble JNICALL
|
||||
Java_org_cagnulen_qdomyoszwift_VirtualGearingBridge_getVirtualGearingShiftUpY(JNIEnv *env, jclass clazz)
|
||||
{
|
||||
Q_UNUSED(env)
|
||||
Q_UNUSED(clazz)
|
||||
QSettings settings;
|
||||
return settings.value(QZSettings::virtual_gearing_shift_up_y, QZSettings::default_virtual_gearing_shift_up_y).toDouble();
|
||||
}
|
||||
|
||||
JNIEXPORT jdouble JNICALL
|
||||
Java_org_cagnulen_qdomyoszwift_VirtualGearingBridge_getVirtualGearingShiftDownX(JNIEnv *env, jclass clazz)
|
||||
{
|
||||
Q_UNUSED(env)
|
||||
Q_UNUSED(clazz)
|
||||
QSettings settings;
|
||||
return settings.value(QZSettings::virtual_gearing_shift_down_x, QZSettings::default_virtual_gearing_shift_down_x).toDouble();
|
||||
}
|
||||
|
||||
JNIEXPORT jdouble JNICALL
|
||||
Java_org_cagnulen_qdomyoszwift_VirtualGearingBridge_getVirtualGearingShiftDownY(JNIEnv *env, jclass clazz)
|
||||
{
|
||||
Q_UNUSED(env)
|
||||
Q_UNUSED(clazz)
|
||||
QSettings settings;
|
||||
return settings.value(QZSettings::virtual_gearing_shift_down_y, QZSettings::default_virtual_gearing_shift_down_y).toDouble();
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_org_cagnulen_qdomyoszwift_VirtualGearingBridge_getVirtualGearingApp(JNIEnv *env, jclass clazz)
|
||||
{
|
||||
Q_UNUSED(env)
|
||||
Q_UNUSED(clazz)
|
||||
QSettings settings;
|
||||
return settings.value(QZSettings::virtual_gearing_app, QZSettings::default_virtual_gearing_app).toInt();
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
QString VirtualGearingDevice::getLastTouchCoordinates()
|
||||
{
|
||||
#ifdef Q_OS_ANDROID
|
||||
QAndroidJniObject result = QAndroidJniObject::callStaticObjectMethod(
|
||||
"org/cagnulen/qdomyoszwift/VirtualGearingBridge",
|
||||
"getLastTouchCoordinates",
|
||||
"()Ljava/lang/String;");
|
||||
if (result.isValid()) {
|
||||
return result.toString();
|
||||
}
|
||||
#endif
|
||||
return "0,0";
|
||||
}
|
||||
|
||||
QString VirtualGearingDevice::getShiftUpCoordinates()
|
||||
{
|
||||
#ifdef Q_OS_ANDROID
|
||||
QAndroidJniObject result = QAndroidJniObject::callStaticObjectMethod(
|
||||
"org/cagnulen/qdomyoszwift/VirtualGearingBridge",
|
||||
"getShiftUpCoordinates",
|
||||
"()Ljava/lang/String;");
|
||||
if (result.isValid()) {
|
||||
return result.toString();
|
||||
}
|
||||
#endif
|
||||
return "0,0";
|
||||
}
|
||||
|
||||
QString VirtualGearingDevice::getShiftDownCoordinates()
|
||||
{
|
||||
#ifdef Q_OS_ANDROID
|
||||
QAndroidJniObject result = QAndroidJniObject::callStaticObjectMethod(
|
||||
"org/cagnulen/qdomyoszwift/VirtualGearingBridge",
|
||||
"getShiftDownCoordinates",
|
||||
"()Ljava/lang/String;");
|
||||
if (result.isValid()) {
|
||||
return result.toString();
|
||||
}
|
||||
#endif
|
||||
return "0,0";
|
||||
}
|
||||
31
src/virtualgearingdevice.h
Normal file
31
src/virtualgearingdevice.h
Normal file
@@ -0,0 +1,31 @@
|
||||
#ifndef VIRTUALGEARINGDEVICE_H
|
||||
#define VIRTUALGEARINGDEVICE_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QQmlEngine>
|
||||
|
||||
class VirtualGearingDevice : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit VirtualGearingDevice(QObject *parent = nullptr);
|
||||
static VirtualGearingDevice* instance();
|
||||
static void registerQmlType();
|
||||
|
||||
public slots:
|
||||
bool isAccessibilityServiceEnabled();
|
||||
void openAccessibilitySettings();
|
||||
void simulateShiftUp();
|
||||
void simulateShiftDown();
|
||||
void simulateTouch(int x, int y);
|
||||
bool isServiceRunning();
|
||||
QString getLastTouchCoordinates();
|
||||
QString getShiftUpCoordinates();
|
||||
QString getShiftDownCoordinates();
|
||||
|
||||
private:
|
||||
static VirtualGearingDevice* m_instance;
|
||||
};
|
||||
|
||||
#endif // VIRTUALGEARINGDEVICE_H
|
||||
Reference in New Issue
Block a user