From 8126a0ac385e95b562947a3dc0174a0ebe1f4dfe Mon Sep 17 00:00:00 2001 From: Hamza-Ayed Date: Tue, 30 Jun 2026 04:42:18 +0300 Subject: [PATCH] Update: 2026-06-30 04:42:17 --- .../executionHistory/executionHistory.bin | Bin 905733 -> 955958 bytes .../executionHistory/executionHistory.lock | Bin 17 -> 17 bytes .../.gradle/8.13/fileHashes/fileHashes.bin | Bin 72765 -> 72965 bytes .../.gradle/8.13/fileHashes/fileHashes.lock | Bin 17 -> 17 bytes .../8.13/fileHashes/resourceHashesCache.bin | Bin 22577 -> 23053 bytes .../buildOutputCleanup.lock | Bin 17 -> 17 bytes .../service/ScraperAccessibilityService.kt | 100 +++++++++++++++--- 7 files changed, 86 insertions(+), 14 deletions(-) diff --git a/android_bot/.gradle/8.13/executionHistory/executionHistory.bin b/android_bot/.gradle/8.13/executionHistory/executionHistory.bin index b849b7bda1665ad0a9147af6fa6aaf384fe7d248..83234c17e6a806bd2aa468934a7254f53534f2a2 100644 GIT binary patch delta 7305 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 F{0m4>M;ibD delta 3625 zcmb_fX;o(vQpSEgM+z5&fG!$fUsTBflSP`K} zh6n{zP(cJDVx&|-!3`R^6-3b>0!o2*7u#q1zP=Ch`<W6c#JD3y0%qpu~Te;QA39sTx#GNv4!rM zT-0177;Z3~)0C#REWGWw=_H4IIy-5Krt)W9xi8*yy{#0D!9f*^I&pw3?@^pq`sNfD z$2c6nVNwoh-~DaZhCAL``i1aKrKEpDHYo$xa}|vu?DNY8-ZgKmx>`<8WeE zF#W`C6PmlM&aN!}Ez2vWm;)2&Hpsf{X1Qw@8H85lcIw z7A3p~jd;&1YD1Uy0Dl%0^#E@cX?uVNi(GnvJEV15X&KU9CoIwf1pp=W0z-EGU@vfF z(e+;H!Sqr}Wgi&F05q`=OlMJiA22m8ZOI)w(SFp1gw&GU_k+6^(PDJ04@fPZb;X*B zPG$*RR9&0D5oeasGg@gC#MB5|tS_-SG5;m9RnIJ4XJqHIViBvjItDw9ysHH6 z798Q=3!nJhpuRBiH;OmkRj$-w6>2vmyGdB1$KMMCNO*zJMIj%l>`d#}kHEo6YqJzo z*7nvltl>PiT#_MY%Q{RH84XevIyEEkn zk)KEnwn)&NQer&o^0ptC3um`a3LmWZG48jWzpFgP+ZCDr4jM%ZT*n>_Y)EeXO?^9_ zXL9X*8S{h{wn#ky%#if}u;fww{vhxqX{41Bm_A`Tw%6xpLJdsi#Y|WDzSOuv|uyehHf5jKOcv$->}6 z>?eRl2w~h;?EIP`C z?ksxBg-$Fo!r@r_Ag%Mop(D#}z@fyRuB8M25D^(39qtk>3*rdR&1z(_A$yLp<%P|=Jpnm%2p)j$ zyllpTIw*Ox)&>O%AV3iS3Q2Z`!1mJX%`y^GN9f z$8Uu{F}n8#SO${-2_Q7qV~Z6E9W0Aw?~+h7=94A1Cn_c=dQ$|oQfAw(RE}#I@5<-BTlHMv7;w9?ZU z@+Y93KKqG|kVdsb4I~`F)*c|BiSe0-7uqt6%T2wPT^a5(_1x(Fbk8~hN^lj81_?Nh zMH5Kqpigu3qf$l1L{-R`a%bGiJIo19F8H`4SR3sF$rRPcL?EI;e zdZB!`HsPgj>xRghY5e@=fN_-+CE7mYul>ETuCyp2VH^P7(6jA3fJLvLO<>QU+7ODj+>WpBLnY)_es+d=~mKe?dsh1YCm#+47v(f$GI*1~*T%7->yc}<1I zVe=-(B!|d5hNb(;*(M!aEcLH(R)lhdUd`mpOR^80v+h+)v}>wKV_Yiv(0K`4MPNzt z@bI-U5uXm-xK5cl#T~^;kgJIjDr6g(bOQqD822d+b?Syvy2dIbPbyAtORNsqSCC3k8=GU_{B!X56VLO`S<`dg z*JFF-vZ!e1pqNnkDwm*8>Rr74`?Kl$ZhO8qy4>pC{Du8>1+zFqs@A5ybc)ttPQg+b zwRUD>Wifrfjg^OOIkZdhdezWLx7>>vlpeQo6+yRYF{RkW?Ke=|0!4MIB6w2F=@K{+B?LWehdNm=k-a z{n5L3Nb$VTRc;~v^%tEZ;&x2#dik#S35#>0}wqLgS-p>h0|c(3d-^hC+t=QNBZEBZs;)$&(1lK>mHtTI z%#YOLXUY~gIvrbC=uB|K@6o&I`i%Nl#0{ZFAU&83)MyboiHkp^DtAgUNow#kl1#nd zqnUp|hN_LOYPH;co@95c-_$KtPW_~2v5+7380I~oTfIZJhlqP9U&|K~ADd{VBOeL# n2nW27nny3S{1*HH#iRNz{zLpI%@w`lSK)0GrwQ-oE1UlVL*|5V diff --git a/android_bot/.gradle/8.13/executionHistory/executionHistory.lock b/android_bot/.gradle/8.13/executionHistory/executionHistory.lock index 2a972215f3c6493bfbe7b47c9b09cecf04e02467..b5566cd5014ff586641e28473df31591cb677a2a 100644 GIT binary patch literal 17 VcmZSHW4!avD({VX3}C<%2LL=q1snhX literal 17 VcmZSHW4!avD({VX3}C=y1pquE1o!{| diff --git a/android_bot/.gradle/8.13/fileHashes/fileHashes.bin b/android_bot/.gradle/8.13/fileHashes/fileHashes.bin index 514a5f28f3c90f46461be30b474e73d8847019bd..aef68768be6513441d2ba72f59035125ee443705 100644 GIT binary patch delta 3239 zcmZWr2~-ow7EK5U$WDZWge453FizMM`6w<4i!APd$_$H3Q1OchvWWPNit&g*AQYIe z2^oPAIEYTG2#Sh-#AOh~-9f*gj*2Mg9A$O+Rn-lLrO)YpudCj@@6~&+x~u-2s-#Z! z_wdNaXg*%W9a0uQl`2xw*@OgNZ}r3ge) zvWSwcS@z-)4(*wc%MLwk;cba-{a|U*x5;VKoEwaT%HztU7pYK9;3T}*yWwLT;$K;s zlFliO4%?X3;yMRC?Xd`rg7F9-2COI;BjTgcbZ^4PI7YGX459jO50>GEj4&qx7cQDM7UAZ*ci_I2|flh0XusNgD>C!`)rgW5m=Ya5i^=* zXl3UFKi18?^5@Sp+aFTEIixF^;Y3#n@3t)oxpsnYzWjA+X3v)@3K35s)=fn0T~O;6 zvc7cXm0POnh4C)N6e0myf=@Xt_CVDkdF=hkd#zQIS`4mFb{%E}4TT)gc?>l}6)?!< zfVdn|N8|7FNZqjjE#?&Xn8RV~o_?U;bb@*9b4hc5w>Z;d*bxG=*II2cm)IH3DmTrq z^_{%0X2c6ZMnpe;S*&#^azOvf8TO4!`$tcLs3W8+WH|kxf?+?TX#VKqsUGw;BbhRc z16@Z@991|D`xX3blNR&oZlY=)aqo|!kvNvgIlfOe+;*i!{B&#oK)uZIwp+^ZB$>Y% z?i2GDuzzhxUH+|-W<{A`d;V90k>Fq+eA6?NtISrM@A;UjxR6k;&K*m)5V4NyuAg-L zh0YCDp&g+uzWsrN8%EQyHx*|;SA)I0;N`N4UznR0j7*~ZXXK(pRN^(d`e_q&J}-uz zxjHY8x!C)4*e{yoc_)=u1Pem0iW<_F_}!ioOijk2XlOK*x!|<|expoeurMfV1tjCq zL3g7%*L0yYHl%awN_7ep16C9vqda5;T8dBzd4Mdt43AmkR#0GlHP(+}Jq7DBpv*&f zC2l9OZSv7PJ2Tumz)pJ1fS^g~cWRR(DTlFmaz?}AzILIq*^m8hzlG15;mI9{g{{A= zqH^``YrhZj?gy82YcNNUs58kf&ByLu=c8~HxO@4^(V>$e7=>ahI2StCsekRr$8` zy6CpU=fqDVhNxGrhPHNzJ`;Ug-zN>uydbZnCU=l!(SyxAzE?c%oU=XLWIE*FB?!`F4taytmtJH)|}A&IK!QD;>v0vv}~j zuUFxiecvnRjf>%|j$vb}g)(qk6c!o5-w524_?ic*bCKr^5dAA^lMEce%wm*M87_88 zTj14-*%6O2uFztyE-n#{kfLJCu_4)SH?UreLGFQX%XfdP>TWEIn+^_0e;ETJJAsTQ z40lB_j!cI2qg1rGp;zWS*Bla`vho%`h)DmZps<%BilM?^4CT1}9Uj#)lw4m;%PZUV zp|fcp{1cBZ3#|<-`V}o$K`l5BFPPlgcpW_Rj_EfzHGzBiKe(3!uYWjyEWxy$V8s$9 zI9Y&xycxL5{qZ;YC?=9%om@{1))m+We#c=mXO%cW6oHG?p6TV1=-I255a=h~dLZgA z$_=E)`yCrmn~A^_?z}c6=IrdzM&i zo04Ypk5Sv3SnM5hbWur2Lx1>sY%$ca9KkUiO_ zs;BJo`C4{&4W6T$MiH7F0(CulQmRl#0zbp>qMIrS!5b%i6;qQ_mi^3{LTx%zi^2DZ zk>_*i9QJ?P%Ut`k2bM@_Ng=%|EOW}4r~Gdg9cImJlAOh+!^4}|B+N#eb{@3GFfC4J zu4*s}mFT)HPYn3Jl1-tav5nlgMV`#2!v&eKYO3Jz7*>;$E`Mx-2svGHEe=w+G4gq& z5-pD!R+PiaU8rdBg||tks+;AGMs%i6i|rPn`_Wns({0Xy&#&Pr1aA-OaK*R;jmK>$ zfy&MGk5sLazo)h8&)d`GLn4F^-LL~$*PCB1yg+%r zMlMKu>O{mmL2t*qjfppoeb{#X`?+p-RKz~;@f9BG^oWTN`N=nCrHP#;0gFo`Z~9j@ PP)^Xf6kgiz;KT0!X}AV< delta 2955 zcmZWr3pkYN9yizuZD=r`&!w?7GFlA^Bki+#I=jVYOLo^Km!(drO>K6=vz>!UwpACyJm9!E5n&Ekv1{n8JaJ`{5$m%mG2kGa9tbSHL#~zT4~pNmz!0mJ|Tr zi-1=uTCV`{Se7XpQ{U(C2e^;9L%EXAw0ylzj)$#%sHVn|8yV*vCEWi3BdJ48t-4$XR*gtmvHu8_PF9TkFvuA^cgO zpI+;eKI8AgM|5~n_0?1Nt0^|tNVo|f!){=4n#&u`w-;Nji9DHJlmFsnl8*`l4gk?n z=$&9!bV2!=^_QbtCHWz^PFvuJQ!iu6jnK6#Glb~z|^VkpmDG%|I_!R2!IiPdvW z!BGodAer*N^oMf2owvU82Z!IhJ?iSgZkD4Ez`87C?Nz-Bhc^6f{w`rkXtteS!1EOO z(3dQ!6impF+e!@53_EK{47@chDqLp#gU^Ek6E{+Ve zimE2ZReSbPL)+=dOOktDu0270@pG(28Ss=NP&NXAUODPZ4j^4-@R|U3J`3yKSXW>@ z0qYDLF^tUHDH|SL^(;kI zS2?mm<;`A|3M}8xSA6#T>|lG(NtRiRU67&7!}@483O5T^&qjgtY&LX~bEt1kzC0=M z;po`r^ofwKRpV5G2{k!{fIK=+F4@&;dzo9)aqiBUhzG$79#K)axd>Q@NYvN2P6fZ0 z+d5y-yHrwVm$iK%DKsoj`2nJzW9q(3GY=mV26`K_n?#l#odyA*}YM-3|__f1m$27nE?_- z5S|BI9FUH61sf$E<=xq_g5}NXVW}rd_8eT+p{>mtlCpVkh4QtNtxL%Y27OYEP22lo zgWvcR?iRN^c);cT2RIn+20{=W7u|DtQtrgwiRiRtoAC}dsc69YUY@but< z+8p#xLW=Y8!k4iE8;Zv|$)^$PSr`K^Y<1f4Y>_QwDRGlN7TK45+LJo+Tiq>*wqfrJ z)(td|8-hXX-LAwY$Zd?*`85_X!lIt)2PY*(FQ-=S`dLLLG3rh!9f~dB2Z@*hz9q1& z;A>ZNf4cIo7XGp<^JXlMOp$RvJgev#a8v01~3pe1pqXx1egE- literal 17 VcmZQpDUVz8=j>v01~3p^2>>-51quKF diff --git a/android_bot/.gradle/8.13/fileHashes/resourceHashesCache.bin b/android_bot/.gradle/8.13/fileHashes/resourceHashesCache.bin index 8654902e1b38c7fc2c511204aafad0578163c273..943d821973f48d64b50f84601faf3bdd4b046ce8 100644 GIT binary patch delta 456 zcmdnEfw6ZB;|3E6#gT`vst&xXs$-aOJo`e~(zPzY}``oWhP;vRmp;8tC+ZNOu zS26wl3@Z3~bF0)sM*dYD|L!OX{)P%VPL`EX5IARi-(5J%JQ*SwF@3YCOa!CGbJ6OM zne)Frg^J#WS@u?beSZC&(gvsz$&*`U0|dVBI&hPrE)U_ge5(Ww`rH0hYJ3k%qpKDAp3!xoArgrWT=^~n^WbbSeSSgZdCjszR{q9 zd$Xg*2YxwYptK|q3xcpf)mBsYs875%_GorzL@nE@G1)X=_T&a{MWY-(HO?jecYb#t z=01LRbg!v;ncO0kAX}0eF)&7?88|7$5!763j&1&{y$ literal 17 VcmZSn@TkOm3HOb23}C?X3IINS1>() @@ -75,9 +78,20 @@ class ScraperAccessibilityService : AccessibilityService() { } else { Log.d(TAG, "No tasks available.") } + // Poll every 5 seconds + delay(5000) + } else { + // We have an active task. Just to be safe, process screen periodically + // in case accessibility events are missed (e.g. app launched but screen static) + withContext(Dispatchers.Main) { + val rootNode = rootInActiveWindow + if (rootNode != null) { + val pkg = rootNode.packageName?.toString() ?: currentAppName + dispatchAutomation(pkg, rootNode) + } + } + delay(1000) // Poll UI state every 1s when active } - // Poll every 5 seconds - delay(5000) } } } @@ -91,11 +105,13 @@ class ScraperAccessibilityService : AccessibilityService() { taxiFPickupDone = false taxiFDestinationDone = false + taxiFSearchTypingTime = 0L currentState = BotState.LAUNCHING_APP // Launch the App val success = AppLauncher.launchApp(this, currentAppName) if (success) { + appLaunchTime = System.currentTimeMillis() currentState = if (currentAppName == "taxif" || currentAppName == "com.taxif.passenger") BotState.NAVIGATING_HOME else BotState.SEARCHING_START Log.i(TAG, "State -> ${currentState}") } else { @@ -120,14 +136,18 @@ class ScraperAccessibilityService : AccessibilityService() { Log.d("HierarchyDump", "--- END SCREEN HIERARCHY DUMP FOR $packageName ---") } - when (packageName) { - "ae.com.yalla.go.dubai.client" -> handleYallaGoAutomation(rootNode) - "com.zakinn.app" -> handleZakinnAutomation(rootNode) - "com.bis.taxi" -> handleTfadalAutomation(rootNode) - "com.careem.acma" -> handleCareemAutomation(rootNode) - "com.ubercab" -> handleUberAutomation(rootNode) - "com.taxif.passenger" -> handleTaxiFAutomation(rootNode) - "me.com.easytaxi" -> handleJeenyAutomation(rootNode) + dispatchAutomation(packageName, rootNode) + } + + private fun dispatchAutomation(packageName: String, rootNode: android.view.accessibility.AccessibilityNodeInfo) { + when { + packageName.contains("yalla") -> handleYallaGoAutomation(rootNode) + packageName.contains("zakinn") -> handleZakinnAutomation(rootNode) + packageName.contains("bis.taxi") -> handleTfadalAutomation(rootNode) + packageName.contains("careem") -> handleCareemAutomation(rootNode) + packageName.contains("ubercab") -> handleUberAutomation(rootNode) + packageName.contains("taxif") -> handleTaxiFAutomation(rootNode) + packageName.contains("easytaxi") -> handleJeenyAutomation(rootNode) } } @@ -405,7 +425,9 @@ class ScraperAccessibilityService : AccessibilityService() { if (nextResult != null && nextResult.optBoolean("has_task", false)) { val nextTask = nextResult.getJSONObject("task") currentState = BotState.IDLE - handleTask(nextTask) + withContext(Dispatchers.Main) { + handleTask(nextTask) + } Log.i(TAG, "Multi-trip: Immediately started next task ${nextTask.optString("task_id")}") } else { Log.i(TAG, "No more tasks, returning to IDLE.") @@ -501,8 +523,9 @@ class ScraperAccessibilityService : AccessibilityService() { Log.d(TAG, "TaxiF Automation event. State: $currentState") when (currentState) { BotState.NAVIGATING_HOME -> { + if (System.currentTimeMillis() - appLaunchTime < 2000) return if (hasJustClickedHome()) return - val rihlaNode = findNodeByText(rootNode, "رحلة") + val rihlaNode = findNodeByText(rootNode, "رحلة") ?: findNodeByText(rootNode, "طلب") if (rihlaNode != null) { var clickable: android.view.accessibility.AccessibilityNodeInfo? = rihlaNode while (clickable != null && !clickable.isClickable) { @@ -510,12 +533,13 @@ class ScraperAccessibilityService : AccessibilityService() { } if (clickable != null) { clickable.performAction(android.view.accessibility.AccessibilityNodeInfo.ACTION_CLICK) - Log.i(TAG, "TaxiF: Clicked 'رحلة' tab, entering trip flow") + Log.i(TAG, "TaxiF: Clicked 'رحلة' or 'طلب' tab, entering trip flow") } else { rihlaNode.performAction(android.view.accessibility.AccessibilityNodeInfo.ACTION_CLICK) - Log.i(TAG, "TaxiF: Clicked 'رحلة' node directly") + Log.i(TAG, "TaxiF: Clicked 'رحلة' or 'طلب' node directly") } taxiFHomeClickTime = System.currentTimeMillis() + currentState = BotState.SEARCHING_START return } currentState = BotState.SEARCHING_START @@ -661,17 +685,65 @@ class ScraperAccessibilityService : AccessibilityService() { } editField.performAction(android.view.accessibility.AccessibilityNodeInfo.ACTION_SET_TEXT, arguments) Log.i(TAG, "TaxiF: Typed '$location' in search field") + taxiFSearchTypingTime = System.currentTimeMillis() + } else { + if (taxiFSearchTypingTime == 0L) { + taxiFSearchTypingTime = System.currentTimeMillis() + } } + if (hasJustClickedSuggestion()) return false + val firstWord = location.split(" ").firstOrNull() ?: location if (clickFirstSuggestion(rootNode, firstWord)) { taxiFSuggestionClickTime = System.currentTimeMillis() Log.i(TAG, "TaxiF: Clicked suggestion matching '$firstWord'") + taxiFSearchTypingTime = 0L return true + } else { + if (System.currentTimeMillis() - taxiFSearchTypingTime > 3000) { + if (clickFirstGenericSuggestion(rootNode)) { + taxiFSuggestionClickTime = System.currentTimeMillis() + Log.i(TAG, "TaxiF: Clicked first generic suggestion as fallback") + taxiFSearchTypingTime = 0L + return true + } + } } return false } + private fun clickFirstGenericSuggestion(rootNode: android.view.accessibility.AccessibilityNodeInfo?): Boolean { + if (rootNode == null) return false + val recycler = findRecyclerView(rootNode) ?: return false + for (i in 0 until recycler.childCount) { + val child = recycler.getChild(i) ?: continue + if (child.isClickable) { + child.performAction(android.view.accessibility.AccessibilityNodeInfo.ACTION_CLICK) + return true + } + } + for (i in 0 until recycler.childCount) { + val child = recycler.getChild(i) ?: continue + val clickableDescendant = findClickableDescendant(child) + if (clickableDescendant != null) { + clickableDescendant.performAction(android.view.accessibility.AccessibilityNodeInfo.ACTION_CLICK) + return true + } + } + return false + } + + private fun findClickableDescendant(node: android.view.accessibility.AccessibilityNodeInfo?): android.view.accessibility.AccessibilityNodeInfo? { + if (node == null) return null + if (node.isClickable) return node + for (i in 0 until node.childCount) { + val res = findClickableDescendant(node.getChild(i)) + if (res != null) return res + } + return null + } + private fun clickFirstSuggestion(rootNode: android.view.accessibility.AccessibilityNodeInfo?, target: String): Boolean { if (rootNode == null) return false val recycler = findRecyclerView(rootNode) ?: return false