Update: 2026-05-14 20:19:28
This commit is contained in:
@@ -14,7 +14,9 @@ data class RideLogRequest(
|
|||||||
val timeToPickup: String,
|
val timeToPickup: String,
|
||||||
val isAccepted: Boolean,
|
val isAccepted: Boolean,
|
||||||
val rawText: String,
|
val rawText: String,
|
||||||
val fingerprint: String
|
val fingerprint: String,
|
||||||
|
val latitude: Double? = null,
|
||||||
|
val longitude: Double? = null
|
||||||
)
|
)
|
||||||
|
|
||||||
data class LocationPoint(
|
data class LocationPoint(
|
||||||
|
|||||||
@@ -11,9 +11,11 @@ class UberParser : NotificationParser {
|
|||||||
|
|
||||||
var price: Double? = null
|
var price: Double? = null
|
||||||
var minutes: Int? = null
|
var minutes: Int? = null
|
||||||
|
var distance: Double? = null
|
||||||
|
|
||||||
val priceRegex = """(\d+\.?\d*)\s*(JOD|د\.أ)""".toRegex()
|
val priceRegex = """(\d+\.?\d*)\s*(JOD|د\.أ)""".toRegex()
|
||||||
val minutesRegex = """(\d+)\s*(min|دقيقة)""".toRegex()
|
val minutesRegex = """(\d+)\s*(min|دقيقة)""".toRegex()
|
||||||
|
val distanceRegex = """(\d+\.?\d*)\s*(km|كم)""".toRegex()
|
||||||
|
|
||||||
val fullText = "$title $text"
|
val fullText = "$title $text"
|
||||||
|
|
||||||
@@ -25,12 +27,15 @@ class UberParser : NotificationParser {
|
|||||||
minutes = it.groupValues[1].toIntOrNull()
|
minutes = it.groupValues[1].toIntOrNull()
|
||||||
}
|
}
|
||||||
|
|
||||||
// We return the request even if price is null, we can filter it later
|
distanceRegex.find(fullText)?.let {
|
||||||
|
distance = it.groupValues[1].toDoubleOrNull()
|
||||||
|
}
|
||||||
|
|
||||||
return RideRequest(
|
return RideRequest(
|
||||||
appPackage = packageName,
|
appPackage = packageName,
|
||||||
priceJod = price,
|
priceJod = price,
|
||||||
minutesAway = minutes,
|
minutesAway = minutes,
|
||||||
distanceKm = null, // Uber usually gives mins, not always distance
|
distanceKm = distance,
|
||||||
title = title,
|
title = title,
|
||||||
text = text
|
text = text
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,5 +1,13 @@
|
|||||||
package com.jordanbot.autoride.service
|
package com.jordanbot.autoride.service
|
||||||
|
|
||||||
|
import android.Manifest
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.content.pm.PackageManager
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
|
import com.google.android.gms.location.FusedLocationProviderClient
|
||||||
|
import com.google.android.gms.location.LocationServices
|
||||||
|
import com.google.android.gms.tasks.Tasks
|
||||||
|
|
||||||
import android.app.Notification
|
import android.app.Notification
|
||||||
import android.service.notification.NotificationListenerService
|
import android.service.notification.NotificationListenerService
|
||||||
import android.service.notification.StatusBarNotification
|
import android.service.notification.StatusBarNotification
|
||||||
@@ -18,6 +26,13 @@ class RideNotificationListener : NotificationListenerService() {
|
|||||||
|
|
||||||
private val serviceScope = CoroutineScope(Dispatchers.IO + SupervisorJob())
|
private val serviceScope = CoroutineScope(Dispatchers.IO + SupervisorJob())
|
||||||
private val filterEngine = FilterEngine()
|
private val filterEngine = FilterEngine()
|
||||||
|
private lateinit var fusedLocationClient: FusedLocationProviderClient
|
||||||
|
|
||||||
|
override fun onCreate() {
|
||||||
|
super.onCreate()
|
||||||
|
fusedLocationClient = LocationServices.getFusedLocationProviderClient(this)
|
||||||
|
}
|
||||||
|
|
||||||
private val parsers = listOf(
|
private val parsers = listOf(
|
||||||
UberParser(),
|
UberParser(),
|
||||||
CareemParser(),
|
CareemParser(),
|
||||||
@@ -35,12 +50,6 @@ class RideNotificationListener : NotificationListenerService() {
|
|||||||
var packageName = sbn.packageName
|
var packageName = sbn.packageName
|
||||||
Log.d("JordanBot", "Received notification from: $packageName")
|
Log.d("JordanBot", "Received notification from: $packageName")
|
||||||
|
|
||||||
// TEMPORARY: Allow Shell notifications for testing
|
|
||||||
if (packageName == "com.android.shell") {
|
|
||||||
Log.d("JordanBot", "Testing mode: Treating Shell notification as Uber")
|
|
||||||
packageName = "com.ubercab.driver"
|
|
||||||
}
|
|
||||||
|
|
||||||
val parser = parsers.find { it.packageName == packageName }
|
val parser = parsers.find { it.packageName == packageName }
|
||||||
if (parser == null) {
|
if (parser == null) {
|
||||||
Log.d("JordanBot", "No parser found for package: $packageName")
|
Log.d("JordanBot", "No parser found for package: $packageName")
|
||||||
@@ -76,6 +85,24 @@ class RideNotificationListener : NotificationListenerService() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun sendLogToBackend(ride: com.jordanbot.autoride.model.RideRequest, isAccepted: Boolean, rawText: String) {
|
private fun sendLogToBackend(ride: com.jordanbot.autoride.model.RideRequest, isAccepted: Boolean, rawText: String) {
|
||||||
|
serviceScope.launch {
|
||||||
|
var lat: Double? = null
|
||||||
|
var lng: Double? = null
|
||||||
|
|
||||||
|
// Try to get current location
|
||||||
|
if (ContextCompat.checkSelfPermission(this@RideNotificationListener, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
|
||||||
|
try {
|
||||||
|
val location = Tasks.await(fusedLocationClient.lastLocation)
|
||||||
|
if (location != null) {
|
||||||
|
lat = location.latitude
|
||||||
|
lng = location.longitude
|
||||||
|
Log.d("JordanBot", "📍 Location attached to ride: $lat, $lng")
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.e("JordanBot", "Failed to get location for ride log", e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val logRequest = RideLogRequest(
|
val logRequest = RideLogRequest(
|
||||||
platform = ride.appPackage,
|
platform = ride.appPackage,
|
||||||
price = ride.priceJod ?: 0.0,
|
price = ride.priceJod ?: 0.0,
|
||||||
@@ -84,10 +111,10 @@ class RideNotificationListener : NotificationListenerService() {
|
|||||||
timeToPickup = ride.minutesAway?.toString() ?: "Unknown",
|
timeToPickup = ride.minutesAway?.toString() ?: "Unknown",
|
||||||
isAccepted = isAccepted,
|
isAccepted = isAccepted,
|
||||||
rawText = rawText,
|
rawText = rawText,
|
||||||
fingerprint = DeviceUtils.getDeviceFingerprint(this)
|
fingerprint = DeviceUtils.getDeviceFingerprint(this@RideNotificationListener),
|
||||||
|
latitude = lat,
|
||||||
|
longitude = lng
|
||||||
)
|
)
|
||||||
|
|
||||||
serviceScope.launch {
|
|
||||||
try {
|
try {
|
||||||
val response = ApiClient.service.logRide(logRequest)
|
val response = ApiClient.service.logRide(logRequest)
|
||||||
if (response.success) {
|
if (response.success) {
|
||||||
|
|||||||
@@ -49,10 +49,12 @@ $timeToPickup = $input['timeToPickup'] ?? 'Unknown';
|
|||||||
$isAccepted = isset($input['isAccepted']) ? (int)$input['isAccepted'] : 0;
|
$isAccepted = isset($input['isAccepted']) ? (int)$input['isAccepted'] : 0;
|
||||||
$rawText = $input['rawText'] ?? '';
|
$rawText = $input['rawText'] ?? '';
|
||||||
$fingerprint = $input['fingerprint'] ?? 'UNKNOWN_DEVICE';
|
$fingerprint = $input['fingerprint'] ?? 'UNKNOWN_DEVICE';
|
||||||
|
$latitude = $input['latitude'] ?? null;
|
||||||
|
$longitude = $input['longitude'] ?? null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$sql = "INSERT INTO rides (fingerprint, platform, price, pickup_distance, dropoff_distance, time_to_pickup, is_accepted, raw_text, created_at)
|
$sql = "INSERT INTO rides (fingerprint, platform, price, pickup_distance, dropoff_distance, time_to_pickup, is_accepted, raw_text, latitude, longitude, created_at)
|
||||||
VALUES (:fingerprint, :platform, :price, :pickup_distance, :dropoff_distance, :time_to_pickup, :is_accepted, :raw_text, NOW())";
|
VALUES (:fingerprint, :platform, :price, :pickup_distance, :dropoff_distance, :time_to_pickup, :is_accepted, :raw_text, :latitude, :longitude, NOW())";
|
||||||
|
|
||||||
$stmt = $pdo->prepare($sql);
|
$stmt = $pdo->prepare($sql);
|
||||||
$stmt->execute([
|
$stmt->execute([
|
||||||
@@ -63,7 +65,9 @@ try {
|
|||||||
':dropoff_distance' => $dropoffDistance,
|
':dropoff_distance' => $dropoffDistance,
|
||||||
':time_to_pickup' => $timeToPickup,
|
':time_to_pickup' => $timeToPickup,
|
||||||
':is_accepted' => $isAccepted,
|
':is_accepted' => $isAccepted,
|
||||||
':raw_text' => $rawText
|
':raw_text' => $rawText,
|
||||||
|
':latitude' => $latitude,
|
||||||
|
':longitude' => $longitude
|
||||||
]);
|
]);
|
||||||
|
|
||||||
http_response_code(201);
|
http_response_code(201);
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ CREATE TABLE IF NOT EXISTS rides (
|
|||||||
time_to_pickup VARCHAR(50),
|
time_to_pickup VARCHAR(50),
|
||||||
is_accepted TINYINT(1) DEFAULT 0,
|
is_accepted TINYINT(1) DEFAULT 0,
|
||||||
raw_text TEXT,
|
raw_text TEXT,
|
||||||
|
latitude DOUBLE DEFAULT NULL,
|
||||||
|
longitude DOUBLE DEFAULT NULL,
|
||||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
INDEX (fingerprint),
|
INDEX (fingerprint),
|
||||||
INDEX (platform)
|
INDEX (platform)
|
||||||
|
|||||||
Reference in New Issue
Block a user