From 0d793fcce107a43431e2c7f840b2e38f34b5776f Mon Sep 17 00:00:00 2001 From: Hamza-Ayed Date: Tue, 30 Jun 2026 04:14:29 +0300 Subject: [PATCH] Update: 2026-06-30 04:14:29 --- .../executionHistory/executionHistory.bin | Bin 905733 -> 905733 bytes .../executionHistory/executionHistory.lock | Bin 17 -> 17 bytes .../.gradle/8.13/fileHashes/fileHashes.bin | Bin 72665 -> 72765 bytes .../.gradle/8.13/fileHashes/fileHashes.lock | Bin 17 -> 17 bytes .../8.13/fileHashes/resourceHashesCache.bin | Bin 21965 -> 22441 bytes .../buildOutputCleanup.lock | Bin 17 -> 17 bytes .../service/ScraperAccessibilityService.kt | 92 +++++++++++------- 7 files changed, 57 insertions(+), 35 deletions(-) diff --git a/android_bot/.gradle/8.13/executionHistory/executionHistory.bin b/android_bot/.gradle/8.13/executionHistory/executionHistory.bin index a91e8dbe5ad9e05ace3cad6dfb09301830e08ecc..edb57f8bc5fa462c0aed7c2a074a3e59f2774abf 100644 GIT binary patch delta 4611 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 O(_2^^6uUPQrSU(NbM}}3 diff --git a/android_bot/.gradle/8.13/fileHashes/fileHashes.lock b/android_bot/.gradle/8.13/fileHashes/fileHashes.lock index 7c18cc16161432d5ed9aec42d9026007a4f744f0..7d30270e55086817a62d4450e629119b0779d1ae 100644 GIT binary patch literal 17 VcmZQpDUVz8=j>v01~3rG1pqYO1kC^d literal 17 VcmZQpDUVz8=j>v01~A~41OPOE1atrZ diff --git a/android_bot/.gradle/8.13/fileHashes/resourceHashesCache.bin b/android_bot/.gradle/8.13/fileHashes/resourceHashesCache.bin index 3ee7fcd48701e549c09d3c7266626db7e2c137e2..c2d40fdd7c170135dc0f6a253125b14cc0d54584 100644 GIT binary patch delta 653 zcmX@RnsMcN#tkMCj3t{*B`g>Prf;z8R!B5m!2kwff}2w%UoZ+BT9*Gsf2U(PRCMNK zSLsInxmn+Zr@mhR5erwGyjMCv;Kr#1m0A0wd!Y)AC$q{t5O~64b;ptEX)RPRbn;!9 zM*jTsQ49KP;-R|RCx^-^2>gGS9kcAFem7L%?#a2bmi+vV4^t9z-a^I7C(o4)(BPQi z?$+{#=POk3?tdr{eJLgV78OTpu?o z{t(}2puxM@(W8e~&KRgv5{LysSU~>MmU@}QZ|_QeK5m-0`$Yfbjov2phO5F~vQN31 zy>44;hM?YGkV-Udw$B#uFk1Kel+^YgTs}1o6sBk@lAg6Sm+tBhvXNcu`g28`6{d>m z5f3=;IA6Y_npgP2Rs7XwxQfZUytR$o91i^z5;o!sc*yl}*DPBJxGazXaeBn+YvMN@ zOOlI)+KUQ**cAbt9u`rtZ>eIs{OPuNd;TZ=K00GQrnZ&tJEJcAkiGXoTUl>4kKAQU Y6}P`-t=J%>w1>w@N->oLnniIhjw!eR8hMjmfdHm6PAeicgl6Gn||z u=RWzaT*Bs1`4fzrO%-P_PJXH+!Sf#q7#KJgZdCjszR{q9Z?mIE4=(_~eJ0WX diff --git a/android_bot/.gradle/buildOutputCleanup/buildOutputCleanup.lock b/android_bot/.gradle/buildOutputCleanup/buildOutputCleanup.lock index 6b52f9cca2b4d19c7e751134ab6b3742991725f1..9a0b5620f2f385408e67aff884c8783e00fe0446 100644 GIT binary patch literal 17 VcmZSn@TkOm3HOb23}C>M0RTPx1xf$_ literal 17 VcmZSn@TkOm3HOb23}C=<3jjW51-JkJ diff --git a/android_bot/app/src/main/java/com/siro/android_bot/service/ScraperAccessibilityService.kt b/android_bot/app/src/main/java/com/siro/android_bot/service/ScraperAccessibilityService.kt index 3f4ad6c9..40db392a 100644 --- a/android_bot/app/src/main/java/com/siro/android_bot/service/ScraperAccessibilityService.kt +++ b/android_bot/app/src/main/java/com/siro/android_bot/service/ScraperAccessibilityService.kt @@ -41,6 +41,7 @@ class ScraperAccessibilityService : AccessibilityService() { private var taxiFDestinationDone = false private val taxiFCollectedPrices = mutableListOf>() private var taxiFPriceScrollAttempts = 0 + private var taxiFReadingPriceStartTime = 0L companion object { private val TAXIF_EXCLUDED_TEXTS = setOf( @@ -397,21 +398,19 @@ class ScraperAccessibilityService : AccessibilityService() { Log.e(TAG, "Failed to submit price.") } - // Wait 3 seconds, then fetch next trip directly (no relaunch) + // Wait 3 seconds for price to settle, then fetch next task directly delay(3000) + val nextResult = workerClient.fetchTask() if (nextResult != null && nextResult.optBoolean("has_task", false)) { val nextTask = nextResult.getJSONObject("task") - val nextApp = nextTask.optString("app") - Log.i(TAG, "Multi-trip: Fetched next task for $nextApp, going directly to SEARCHING_START") - currentTask = nextTask - currentAppName = nextApp taxiFPickupDone = false taxiFDestinationDone = false currentState = BotState.SEARCHING_START + Log.i(TAG, "TaxiF: Multi-trip fetched next task ${nextTask.optString("task_id")}, state -> SEARCHING_START") } else { - Log.d(TAG, "Multi-trip: No more tasks, going IDLE.") + Log.i(TAG, "No more tasks, returning to IDLE.") currentState = BotState.IDLE currentTask = null } @@ -551,6 +550,7 @@ class ScraperAccessibilityService : AccessibilityService() { } taxiFDestinationDone = true currentState = BotState.READING_PRICE + taxiFReadingPriceStartTime = System.currentTimeMillis() taxiFCollectedPrices.clear() taxiFPriceScrollAttempts = 0 return @@ -561,7 +561,16 @@ class ScraperAccessibilityService : AccessibilityService() { } } BotState.READING_PRICE -> { - if (!hasJustClickedSuggestion()) { + if (hasJustClickedSuggestion()) return + if (System.currentTimeMillis() - taxiFReadingPriceStartTime < 2000) return + + val ecoPrice = getEcoPrice(rootNode) + if (ecoPrice != null && ecoPrice > 0) { + Log.i(TAG, "TaxiF: Found ECO price: $ecoPrice JOD") + submitPriceToServer("$ecoPrice JOD") + currentState = BotState.IDLE + } else if (System.currentTimeMillis() - taxiFReadingPriceStartTime > 15000) { + Log.w(TAG, "TaxiF: ECO price not found within 15s timeout, falling back to collectAndScrollPrices") collectAndScrollPrices(rootNode) } } @@ -570,44 +579,34 @@ class ScraperAccessibilityService : AccessibilityService() { } private fun hasJustClickedHome(): Boolean { - return (System.currentTimeMillis() - taxiFHomeClickTime) < 1500 + return (System.currentTimeMillis() - taxiFHomeClickTime) < 500 } private fun hasJustClickedLocation(): Boolean { - return (System.currentTimeMillis() - taxiFLocationClickTime) < 1500 + return (System.currentTimeMillis() - taxiFLocationClickTime) < 500 } private fun hasJustClickedSuggestion(): Boolean { - return (System.currentTimeMillis() - taxiFSuggestionClickTime) < 1500 - } - - private fun getLocationTexts(node: android.view.accessibility.AccessibilityNodeInfo?): List { - val texts = mutableListOf() - collectLocationTexts(node, texts) - return texts - } - - private fun collectLocationTexts(node: android.view.accessibility.AccessibilityNodeInfo?, texts: MutableList) { - if (node == null) return - val text = node.text?.toString()?.trim() ?: "" - val className = node.className?.toString() ?: "" - val isEditText = className == "android.widget.EditText" || node.isEditable - if (text.isNotBlank() && text.length > 2 && !isEditText && TAXIF_EXCLUDED_TEXTS.none { text.contains(it) }) { - texts.add(text) - } - for (i in 0 until node.childCount) { - collectLocationTexts(node.getChild(i), texts) - } + return (System.currentTimeMillis() - taxiFSuggestionClickTime) < 500 } private fun shouldEditLocation(rootNode: android.view.accessibility.AccessibilityNodeInfo, task: JSONObject, isPickup: Boolean): Boolean { - val locationTexts = getLocationTexts(rootNode) + val locationNodes = getLocationTextNodes(rootNode) val taskLoc = if (isPickup) task.optString("start_location", "") else task.optString("end_location", "") if (taskLoc.isEmpty()) return false - val matchFound = locationTexts.any { text -> - text.contains(taskLoc, ignoreCase = true) || taskLoc.contains(text, ignoreCase = true) + + val rowNode = if (isPickup) { + locationNodes.firstOrNull() + } else { + val destIdx = locationNodes.indexOfFirst { it.text?.toString() == "عنوان الإنزال" } + if (destIdx >= 0) locationNodes[destIdx] else locationNodes.getOrNull(1) } - Log.d(TAG, "TaxiF: Location texts=$locationTexts, taskLoc=$taskLoc, matchFound=$matchFound") + + val rowText = rowNode?.text?.toString()?.trim() ?: "" + val matchFound = rowText.contains(taskLoc, ignoreCase = true) || taskLoc.contains(rowText, ignoreCase = true) + + Log.d(TAG, "TaxiF: shouldEditLocation(isPickup=$isPickup): rowText='$rowText', taskLoc='$taskLoc', matchFound=$matchFound, locationNodes=[${locationNodes.joinToString { it.text?.toString() ?: "" }}]") + return !matchFound } @@ -656,7 +655,9 @@ class ScraperAccessibilityService : AccessibilityService() { if (editTexts.isEmpty()) return false val editField = editTexts[0] val currentText = editField.text?.toString() ?: "" - if (currentText != location) { + val normalizedCurrent = currentText.replace("-", " ").replace("\\s+".toRegex(), " ").trim() + val normalizedLocation = location.replace("-", " ").replace("\\s+".toRegex(), " ").trim() + if (!normalizedCurrent.contains(normalizedLocation, ignoreCase = true)) { val arguments = android.os.Bundle().apply { putCharSequence(android.view.accessibility.AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE, location) } @@ -689,7 +690,9 @@ class ScraperAccessibilityService : AccessibilityService() { private fun suggestionContainsText(node: android.view.accessibility.AccessibilityNodeInfo?, target: String): Boolean { if (node == null) return false val text = node.text?.toString() ?: "" - if (text.contains(target, ignoreCase = true)) return true + val normalizedText = text.replace("-", " ").replace("\\s+".toRegex(), " ").trim() + val normalizedTarget = target.replace("-", " ").replace("\\s+".toRegex(), " ").trim() + if (normalizedText.contains(normalizedTarget, ignoreCase = true)) return true for (i in 0 until node.childCount) { if (suggestionContainsText(node.getChild(i), target)) return true } @@ -780,6 +783,25 @@ class ScraperAccessibilityService : AccessibilityService() { } } + private fun getEcoPrice(rootNode: android.view.accessibility.AccessibilityNodeInfo?): Double? { + if (rootNode == null) return null + val recycler = findHorizontalRecyclerView(rootNode) ?: return null + for (i in 0 until recycler.childCount) { + val card = recycler.getChild(i) ?: continue + if (findNodeByText(card, "ECO") != null) { + val jodNode = findNodeByText(card, "JOD") ?: continue + val text = jodNode.text?.toString() ?: continue + val converted = arabicToWestern(text) + val match = Regex("""(\d+\.?\d*)""").find(converted) + if (match != null) { + val price = match.value.toDoubleOrNull() + if (price != null && price > 0) return price + } + } + } + return null + } + private fun handleJeenyAutomation(rootNode: android.view.accessibility.AccessibilityNodeInfo) { val task = currentTask ?: return Log.d(TAG, "Jeeny Automation event. State: $currentState")