Skip to content

Commit 7e7c31d

Browse files
madeyeclaudeMax Lv
authored
WIP: Rewrite project in Kotlin - core classes and utilities (#34)
* WIP: Rewrite project in Kotlin - core classes and utilities - Add Kotlin plugin to build.gradle files - Convert core app classes: ProxyDroidApplication, Profile, ProxyedApp - Convert services: ProxyDroidService, ProxyDroidVpnService - Convert receivers: ProxyDroidReceiver, ConnectivityBroadcastReceiver - Convert widget: ProxyDroidWidgetProvider - Convert JNI interfaces: Exec, Tun2SocksHelper - Convert utility classes: Utils, Constraints, Option, ImageLoader, ImageLoaderFactory, RegexValidator, LocalProxyServer - Convert helper: InnerSocketBuilder This is work in progress - remaining files to convert: - UI activities (ProxyDroid, AppManager, BypassListActivity, FileChooser) - PAC selector classes - Adapters and validators - Test files https://claude.ai/code/session_01A8JRXuv4RL3LWQCZq4QDr9 * Complete Kotlin rewrite of ProxyDroid project This commit completes the full conversion of the ProxyDroid Android project from Java to Kotlin. Changes include: - Updated build.gradle files with Kotlin plugin and dependencies - Converted all 36 Java source files to Kotlin - Converted all test files to Kotlin - Removed all original Java files Converted files by package: org.proxydroid: - ProxyDroid, ProxyDroidApplication, Profile, ProxyedApp - ProxyDroidService, ProxyDroidVpnService - AppManager, BypassListActivity, FileChooser, FileArrayAdapter - ConnectivityBroadcastReceiver, ProxyDroidReceiver - ProxyDroidWidgetProvider - Exec, InnerSocketBuilder, DomainValidator org.proxydroid.utils: - Utils, Constraints, Option, Base64 - ImageLoader, ImageLoaderFactory - LocalProxyServer, Tun2SocksHelper, RegexValidator com.btr.proxy.selector.pac: - PacProxySelector, PacScriptParser, PacScriptSource - RhinoPacScriptParser, UrlPacScriptSource - PacScriptMethods, ScriptMethods - Proxy, ProxyException, ProxyEvaluationException com.ksmaze.android.preference: - ListPreferenceMultiSelect Test files: - ExampleUnitTest, ExampleInstrumentedTest - LocalHttpProxyTest https://claude.ai/code/session_01A8JRXuv4RL3LWQCZq4QDr9 * Fix Kotlin compilation errors - Add missing Base64.kt utility class that wraps android.util.Base64 - Fix duplicate companion object in AppManager.kt (merged into one) - Add missing vpn_running string resource https://claude.ai/code/session_01A8JRXuv4RL3LWQCZq4QDr9 * Add missing init() method to Profile class The ProxyDroid activity calls mProfile.init() to reset profile values, but this method was missing after the Kotlin conversion. https://claude.ai/code/session_01A8JRXuv4RL3LWQCZq4QDr9 * Fix Kotlin compilation errors - Change androidx.preference.PreferenceManager to android.preference.PreferenceManager (androidx.preference requires additional dependency) - Add explicit type parameter to emptyList<String>() in ConnectivityBroadcastReceiver https://claude.ai/code/session_01A8JRXuv4RL3LWQCZq4QDr9 * Fix ProxyedApp and AppManager compilation errors - Add missing isProxyed and isEnabled properties to ProxyedApp - Make username, procname, name nullable in ProxyedApp - Fix OnScrollListener reference to use AbsListView.OnScrollListener - Add null check before Arrays.binarySearch for nullable username https://claude.ai/code/session_01A8JRXuv4RL3LWQCZq4QDr9 * Fix Kotlin compilation error in ImageLoader.kt Cast lock object to Object before calling notifyAll() since Kotlin's Any type doesn't have the notifyAll() method. This is consistent with the existing wait() call pattern on line 121. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: Max Lv <mlv@MaxdeMac-mini.local>
1 parent c6361f2 commit 7e7c31d

81 files changed

Lines changed: 4796 additions & 11480 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

app/build.gradle

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
plugins {
22
id 'com.android.application'
3+
id 'org.jetbrains.kotlin.android'
34
}
45

56
android {
@@ -35,6 +36,10 @@ android {
3536
targetCompatibility JavaVersion.VERSION_11
3637
}
3738

39+
kotlinOptions {
40+
jvmTarget = '11'
41+
}
42+
3843
externalNativeBuild {
3944
cmake {
4045
version '3.22.1'
@@ -51,6 +56,8 @@ dependencies {
5156
implementation fileTree(dir: 'libs', include: ['*.jar'])
5257
implementation 'androidx.appcompat:appcompat:1.6.1'
5358
implementation 'com.google.android.material:material:1.9.0'
59+
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
60+
implementation 'androidx.core:core-ktx:1.10.1'
5461
// Exclude JUnit from json-simple (it pulls junit as compile dependency)
5562
implementation('com.googlecode.json-simple:json-simple:1.1.1') {
5663
exclude group: 'junit', module: 'junit'

app/src/androidTest/java/org/proxydroid/ExampleInstrumentedTest.java

Lines changed: 0 additions & 27 deletions
This file was deleted.
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package org.proxydroid
2+
3+
import androidx.test.ext.junit.runners.AndroidJUnit4
4+
import androidx.test.platform.app.InstrumentationRegistry
5+
import org.junit.Test
6+
import org.junit.runner.RunWith
7+
import org.junit.Assert.*
8+
9+
@RunWith(AndroidJUnit4::class)
10+
class ExampleInstrumentedTest {
11+
@Test
12+
fun useAppContext() {
13+
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
14+
assertEquals("org.proxydroid", appContext.packageName)
15+
}
16+
}

app/src/main/java/com/btr/proxy/selector/pac/PacProxySelector.java

Lines changed: 0 additions & 144 deletions
This file was deleted.
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
package com.btr.proxy.selector.pac
2+
3+
import android.util.Log
4+
import java.net.URI
5+
6+
class PacProxySelector(pacSource: PacScriptSource) {
7+
8+
companion object {
9+
private const val PAC_SOCKS = "SOCKS"
10+
private const val PAC_DIRECT = "DIRECT"
11+
private const val PAC_HTTPS = "HTTPS"
12+
private const val TAG = "ProxyDroid.PAC"
13+
}
14+
15+
private var pacScriptParser: PacScriptParser? = null
16+
17+
init {
18+
selectEngine(pacSource)
19+
}
20+
21+
private fun selectEngine(pacSource: PacScriptSource) {
22+
try {
23+
pacScriptParser = RhinoPacScriptParser(pacSource)
24+
} catch (e: Exception) {
25+
Log.e(TAG, "PAC parser error.", e)
26+
}
27+
}
28+
29+
fun select(uri: URI): List<Proxy>? {
30+
if (uri.host == null) {
31+
throw IllegalArgumentException("URI must not be null.")
32+
}
33+
34+
val scriptSource = pacScriptParser?.getScriptSource()
35+
if (scriptSource.toString().contains(uri.host)) {
36+
return null
37+
}
38+
39+
return findProxy(uri)
40+
}
41+
42+
private fun findProxy(uri: URI): List<Proxy>? {
43+
return try {
44+
val proxies = mutableListOf<Proxy>()
45+
val parseResult = pacScriptParser?.evaluate(uri.toString(), uri.host) ?: return null
46+
val proxyDefinitions = parseResult.split(";")
47+
48+
for (proxyDef in proxyDefinitions) {
49+
if (proxyDef.trim().isNotEmpty()) {
50+
proxies.add(buildProxyFromPacResult(proxyDef))
51+
}
52+
}
53+
proxies
54+
} catch (e: ProxyEvaluationException) {
55+
Log.e(TAG, "PAC resolving error.", e)
56+
null
57+
}
58+
}
59+
60+
private fun buildProxyFromPacResult(pacResult: String?): Proxy {
61+
if (pacResult == null || pacResult.trim().length < 6) {
62+
return Proxy.NO_PROXY
63+
}
64+
65+
val proxyDef = pacResult.trim()
66+
if (proxyDef.uppercase().startsWith(PAC_DIRECT)) {
67+
return Proxy.NO_PROXY
68+
}
69+
70+
var type = Proxy.TYPE_HTTP
71+
if (proxyDef.uppercase().startsWith(PAC_SOCKS)) {
72+
type = Proxy.TYPE_SOCKS5
73+
}
74+
if (proxyDef.uppercase().startsWith(PAC_HTTPS)) {
75+
type = Proxy.TYPE_HTTPS
76+
}
77+
78+
var host = proxyDef.substring(6)
79+
var port = if (type == Proxy.TYPE_HTTPS) 443 else 80
80+
81+
val indexOfPort = host.indexOf(':')
82+
if (indexOfPort != -1) {
83+
port = host.substring(indexOfPort + 1).trim().toInt()
84+
host = host.substring(0, indexOfPort).trim()
85+
}
86+
87+
return Proxy(host, port, type)
88+
}
89+
}

0 commit comments

Comments
 (0)