diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..aa724b7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,15 @@ +*.iml +.gradle +/local.properties +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +.DS_Store +/build +/captures +.externalNativeBuild +.cxx +local.properties diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..26d3352 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..61a9130 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..5cd135a --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,20 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml new file mode 100644 index 0000000..958a5be --- /dev/null +++ b/.idea/jarRepositories.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..d5d35ec --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,9 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml new file mode 100644 index 0000000..797acea --- /dev/null +++ b/.idea/runConfigurations.xml @@ -0,0 +1,10 @@ + + + + + + \ No newline at end of file diff --git a/app/.gitignore b/app/.gitignore new file mode 100644 index 0000000..42afabf --- /dev/null +++ b/app/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle new file mode 100644 index 0000000..945a1ed --- /dev/null +++ b/app/build.gradle @@ -0,0 +1,55 @@ +plugins { + id 'com.android.application' + id 'kotlin-android' +} + +android { + compileSdkVersion 30 + buildToolsVersion "30.0.3" + + defaultConfig { + applicationId "github.arash.kotlin.proxychecker" + minSdkVersion 21 + targetSdkVersion 30 + versionCode 1 + versionName "1.0" + + archivesBaseName = "ProxyChecker - v$versionCode" + + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + kotlinOptions { + jvmTarget = '1.8' + } + buildFeatures{ + viewBinding true + } +} + +dependencies { + + implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" + implementation 'androidx.core:core-ktx:1.6.0' + implementation 'androidx.appcompat:appcompat:1.3.0' + implementation 'com.google.android.material:material:1.4.0' + implementation 'androidx.constraintlayout:constraintlayout:2.0.4' + testImplementation 'junit:junit:4.+' + androidTestImplementation 'androidx.test.ext:junit:1.1.3' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' + + //OkHTTP & FastAndroidNetworking + implementation 'com.squareup.okhttp3:okhttp:4.9.0' + implementation 'com.amitshekhar.android:android-networking:1.0.2' + +} \ No newline at end of file diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro new file mode 100644 index 0000000..481bb43 --- /dev/null +++ b/app/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/app/release/ProxyChecker - v1-release.apk b/app/release/ProxyChecker - v1-release.apk new file mode 100644 index 0000000..a8dee90 Binary files /dev/null and b/app/release/ProxyChecker - v1-release.apk differ diff --git a/app/release/output-metadata.json b/app/release/output-metadata.json new file mode 100644 index 0000000..acfa00d --- /dev/null +++ b/app/release/output-metadata.json @@ -0,0 +1,18 @@ +{ + "version": 2, + "artifactType": { + "type": "APK", + "kind": "Directory" + }, + "applicationId": "github.arash.kotlin.proxychecker", + "variantName": "release", + "elements": [ + { + "type": "SINGLE", + "filters": [], + "versionCode": 1, + "versionName": "1.0", + "outputFile": "ProxyChecker - v1-release.apk" + } + ] +} \ No newline at end of file diff --git a/app/src/androidTest/java/github/arash/kotlin/proxychecker/ExampleInstrumentedTest.kt b/app/src/androidTest/java/github/arash/kotlin/proxychecker/ExampleInstrumentedTest.kt new file mode 100644 index 0000000..b8b9530 --- /dev/null +++ b/app/src/androidTest/java/github/arash/kotlin/proxychecker/ExampleInstrumentedTest.kt @@ -0,0 +1,24 @@ +package github.arash.kotlin.proxychecker + +import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.ext.junit.runners.AndroidJUnit4 + +import org.junit.Test +import org.junit.runner.RunWith + +import org.junit.Assert.* + +/** + * Instrumented test, which will execute on an Android device. + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +@RunWith(AndroidJUnit4::class) +class ExampleInstrumentedTest { + @Test + fun useAppContext() { + // Context of the app under test. + val appContext = InstrumentationRegistry.getInstrumentation().targetContext + assertEquals("github.arash.kotlin.proxychecker", appContext.packageName) + } +} \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..4176e40 --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/java/github/arash/kotlin/proxychecker/G.java b/app/src/main/java/github/arash/kotlin/proxychecker/G.java new file mode 100644 index 0000000..9fe9f66 --- /dev/null +++ b/app/src/main/java/github/arash/kotlin/proxychecker/G.java @@ -0,0 +1,11 @@ +package github.arash.kotlin.proxychecker; + +public class G { + + public static String SaveCredential_SharedPreferencesKey = "SaveCredentialP"; + + public static String ProxyAddress_SharedPreferencesKey = "ProxyAddressP"; + public static String PortNumber_SharedPreferencesKey = "PortNumberP"; + public static String Username_SharedPreferencesKey = "UsernameP"; + public static String Password_SharedPreferencesKey = "PasswordP"; +} diff --git a/app/src/main/java/github/arash/kotlin/proxychecker/MainActivity.kt b/app/src/main/java/github/arash/kotlin/proxychecker/MainActivity.kt new file mode 100644 index 0000000..eabdb10 --- /dev/null +++ b/app/src/main/java/github/arash/kotlin/proxychecker/MainActivity.kt @@ -0,0 +1,246 @@ +package github.arash.kotlin.proxychecker + +import android.app.AlertDialog +import android.content.Context +import android.content.Intent +import android.net.ConnectivityManager +import android.net.Uri +import android.os.Bundle +import android.util.Log +import android.view.LayoutInflater +import android.view.Menu +import android.view.MenuItem +import android.view.View +import android.view.View.GONE +import android.view.View.VISIBLE +import android.widget.CompoundButton +import android.widget.TextView +import android.widget.Toast +import androidx.appcompat.app.AppCompatActivity +import androidx.appcompat.app.AppCompatDelegate +import com.androidnetworking.AndroidNetworking +import com.androidnetworking.error.ANError +import com.androidnetworking.interfaces.JSONObjectRequestListener +import com.google.android.material.bottomsheet.BottomSheetBehavior +import com.google.android.material.bottomsheet.BottomSheetDialog +import github.arash.kotlin.proxychecker.databinding.ActivityMainBinding +import github.arash.kotlin.proxychecker.databinding.DesignSettingBtmBinding +import github.arash.kotlin.proxychecker.databinding.DesignTelegramInputDialogBinding +import okhttp3.OkHttpClient +import org.json.JSONObject +import java.lang.Exception +import java.net.Authenticator +import java.net.InetSocketAddress +import java.net.PasswordAuthentication +import java.net.Proxy + +class MainActivity : AppCompatActivity() { + + private lateinit var binding: ActivityMainBinding + + override fun onCreate(savedInstanceState: Bundle?) { + AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO) + super.onCreate(savedInstanceState) + binding = ActivityMainBinding.inflate(layoutInflater) + setContentView(binding.root) + setSupportActionBar(binding.toolbar) + + AndroidNetworking.initialize(this) + PreferenceHelper.initialize(this) + + binding.ProxyAddress.setText( + PreferenceHelper.getInstance().getString(G.ProxyAddress_SharedPreferencesKey, "") + ) + binding.ProxyPort.setText( + PreferenceHelper.getInstance().getString(G.PortNumber_SharedPreferencesKey, "") + ) + binding.ProxyUsername.setText( + PreferenceHelper.getInstance().getString(G.Username_SharedPreferencesKey, "") + ) + binding.ProxyPassword.setText( + PreferenceHelper.getInstance().getString(G.Password_SharedPreferencesKey, "") + ) + + PreferenceHelper.getInstance().getString(G.PortNumber_SharedPreferencesKey, "") + PreferenceHelper.getInstance().getString(G.Username_SharedPreferencesKey, "") + PreferenceHelper.getInstance().getString(G.Password_SharedPreferencesKey, "") + + + val connectivityManager: ConnectivityManager = + getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager + if (connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_VPN)!!.isConnectedOrConnecting) + binding.vpnAlertTV.visibility = VISIBLE + + var okHttpClient: OkHttpClient + binding.StartTheTestButton.setOnClickListener { + binding.ProgressBar.visibility = VISIBLE + binding.StartTheTestButton.text = "Please Wait..." + binding.StartTheTestButton.isEnabled = false + + //Proxy Type + if (binding.ProxyTypeToggleGroup.checkedButtonId == R.id.ProxyTypeHTTPS) + okHttpClient = OkHttpClient.Builder() + .proxy( + Proxy( + Proxy.Type.HTTP, InetSocketAddress( + binding.ProxyAddress.text.toString(), + binding.ProxyPort.text.toString().toInt() + ) + ) + ).build() + else + okHttpClient = OkHttpClient.Builder().proxy( + Proxy( + Proxy.Type.SOCKS, InetSocketAddress( + binding.ProxyAddress.text.toString(), + binding.ProxyPort.text.toString().toInt() + ) + ) + ).build() + + //Proxy Credential + Authenticator.setDefault(object : Authenticator() { + override fun getPasswordAuthentication(): PasswordAuthentication? { + if (requestingHost.equals( + binding.ProxyAddress.text.toString(), + ) + ) if (binding.ProxyPort.text.toString() + .toInt() == requestingPort + ) return PasswordAuthentication( + binding.ProxyUsername.text.toString(), + binding.ProxyPassword.text.toString().toCharArray() + ) + return null + } + }) + + //Make a Get Request + AndroidNetworking.get("http://ip-api.com/json") + .setOkHttpClient(okHttpClient) + .build() + .getAsJSONObject(object : JSONObjectRequestListener { + override fun onResponse(response: JSONObject?) { + Log.i("TheMainTAG", "Response: ${response.toString()}") + if (response!!.get("status").equals("success")) { + val resultBottomSheet = BottomSheetDialog(this@MainActivity) + resultBottomSheet.setContentView(R.layout.design_result_btm) + + val resultFinalIP: TextView? = + resultBottomSheet.findViewById(R.id.resultFinalIP) + val resultCountry: TextView? = + resultBottomSheet.findViewById(R.id.resultCountry) + val resultCity: TextView? = + resultBottomSheet.findViewById(R.id.resultCity) + val resultISP: TextView? = + resultBottomSheet.findViewById(R.id.resultISP) + + resultFinalIP?.text = response.get("query").toString() + resultCountry?.text = response.get("country").toString() + resultCity?.text = response.get("city").toString() + resultISP?.text = response.get("isp").toString() + resultBottomSheet.behavior.state = BottomSheetBehavior.STATE_EXPANDED + resultBottomSheet.show() + binding.ProgressBar.visibility = GONE + binding.StartTheTestButton.text = "Test The Proxy" + binding.StartTheTestButton.isEnabled = true + } + } + + override fun onError(anError: ANError?) { + binding.ProgressBar.visibility = GONE + binding.StartTheTestButton.text = "Test The Proxy" + binding.StartTheTestButton.isEnabled = true + } + }) + + PreferenceHelper.getInstance().setString( + G.ProxyAddress_SharedPreferencesKey, + binding.ProxyAddress.text.toString() + ) + PreferenceHelper.getInstance() + .setString(G.PortNumber_SharedPreferencesKey, binding.ProxyPort.text.toString()) + + if (PreferenceHelper.getInstance().getBoolean(G.SaveCredential_SharedPreferencesKey)) { + PreferenceHelper.getInstance() + .setString( + G.Username_SharedPreferencesKey, + binding.ProxyUsername.text.toString() + ) + PreferenceHelper.getInstance() + .setString( + G.Password_SharedPreferencesKey, + binding.ProxyPassword.text.toString() + ) + } + } + } + + override fun onCreateOptionsMenu(menu: Menu?): Boolean { + val inflater = menuInflater + inflater.inflate(R.menu.toolbar_menu, menu) + return super.onCreateOptionsMenu(menu) + } + + override fun onOptionsItemSelected(item: MenuItem): Boolean { + when (item.itemId) { + R.id.Action_Github -> + startActivity( + Intent( + Intent.ACTION_VIEW, + Uri.parse("https://github.com/MrArashAzizi/Proxy-Checking-Tool") + ) + ) + R.id.Action_Setting -> settingBottomSheetDialog() + + R.id.Action_ImportTelegramProxy -> importTelegramProxy() + } + return super.onOptionsItemSelected(item) + } + + private fun settingBottomSheetDialog() { + val settingBTM = BottomSheetDialog(this) + val inflater: LayoutInflater = getSystemService(LAYOUT_INFLATER_SERVICE) as LayoutInflater + val view: View = inflater.inflate(R.layout.design_setting_btm, null) + val settingBottomSheetBinding: DesignSettingBtmBinding = + DesignSettingBtmBinding.bind(view) + + settingBottomSheetBinding.SettingSaveCredential.isChecked = + PreferenceHelper.getInstance().getBoolean(G.SaveCredential_SharedPreferencesKey) + settingBottomSheetBinding.SettingSaveCredential.setOnCheckedChangeListener { _, isChecked -> + PreferenceHelper.getInstance() + .setBoolean(G.SaveCredential_SharedPreferencesKey, isChecked) + } + + settingBTM.setContentView(view) + settingBTM.behavior.state = BottomSheetBehavior.STATE_EXPANDED + settingBTM.show() + } + + private fun importTelegramProxy() { + val inputDialog: AlertDialog = AlertDialog.Builder(this@MainActivity).create() + val inflater: LayoutInflater = getSystemService(LAYOUT_INFLATER_SERVICE) as LayoutInflater + val view: View = inflater.inflate(R.layout.design_telegram_input_dialog, null) + val telegramProxyInputBinding: DesignTelegramInputDialogBinding = + DesignTelegramInputDialogBinding.bind(view) + + telegramProxyInputBinding.btnOK.setOnClickListener { + try { + + val myURI: Uri = Uri.parse(telegramProxyInputBinding.TelegramProxy.text.toString()) + binding.ProxyAddress.setText(myURI.getQueryParameter("server").toString()) + binding.ProxyPort.setText(myURI.getQueryParameter("port").toString()) + + if (myURI.equals("username")) { + binding.ProxyUsername.setText(myURI.getQueryParameter("user").toString()) + binding.ProxyPassword.setText(myURI.getQueryParameter("pass").toString()) + } + inputDialog.dismiss() + } catch (ex: Exception) { + } + } + telegramProxyInputBinding.btnCancel.setOnClickListener { inputDialog.dismiss() } + inputDialog.setView(telegramProxyInputBinding.root) + inputDialog.show() + } + +} \ No newline at end of file diff --git a/app/src/main/java/github/arash/kotlin/proxychecker/PreferenceHelper.java b/app/src/main/java/github/arash/kotlin/proxychecker/PreferenceHelper.java new file mode 100644 index 0000000..a50fa87 --- /dev/null +++ b/app/src/main/java/github/arash/kotlin/proxychecker/PreferenceHelper.java @@ -0,0 +1,99 @@ +package github.arash.kotlin.proxychecker; + +import android.app.Activity; +import android.content.Context; +import android.content.SharedPreferences; +import android.preference.PreferenceManager; + +public class PreferenceHelper { + private static SharedPreferences pref; + private static PreferenceHelper prefHelper; + + public PreferenceHelper(Context context) { + pref = PreferenceManager.getDefaultSharedPreferences(context); + } + + public Boolean containsKey(String key) { + return pref.contains(key); + } + + public void clearPrefs() { + SharedPreferences.Editor editor = pref.edit(); + editor.clear(); + editor.apply(); + } + + public static void initialize(Context appContext) { + if (appContext == null) { + throw new NullPointerException("Provided application context is null"); + } + if (prefHelper == null) { + synchronized (PreferenceHelper.class) { + if (prefHelper == null) { + prefHelper = new PreferenceHelper(appContext); + } + } + } + } + + public static PreferenceHelper getInstance() { + if (prefHelper == null) { + throw new IllegalStateException( + "SharedPrefsManager is not initialized, call initialize(applicationContext) " + + "static method first"); + } + return prefHelper; + } + + public void setString(String key, String value) { + SharedPreferences.Editor editor = pref.edit(); + editor.putString(key, value); + editor.apply(); + } + + public static void removeKey(String key) { + pref.edit().remove(key).apply(); + } + + public String getString(String key, String defValue) { + return pref.getString(key, defValue); + } + + public Boolean getBoolean(String key) { + return pref.getBoolean(key, false); + } + + public void setBoolean(String key, Boolean isBoolean) { + SharedPreferences.Editor editor = pref.edit(); + editor.putBoolean(key, isBoolean); + editor.apply(); + + } + + + public void setInt(String key, int value) { + SharedPreferences.Editor editor = pref.edit(); + editor.putInt(key, value); + editor.apply(); + } + + public void loggedOut() { + clearPrefs(); + } + + public int getInt(String key) { + return pref.getInt(key, 0); + } + + public void toPrev8(Activity activity, String key, Boolean isBoolean) { + SharedPreferences sharedPref = activity.getPreferences(Context.MODE_PRIVATE); + SharedPreferences.Editor editor = sharedPref.edit(); + editor.putBoolean(key, isBoolean); + editor.apply(); + } + + public boolean fromPrev8(Activity activity, String key) { + SharedPreferences sharedPref = activity.getPreferences(Context.MODE_PRIVATE); + return sharedPref.getBoolean(key, false); + } +} \ No newline at end of file diff --git a/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml new file mode 100644 index 0000000..2b068d1 --- /dev/null +++ b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/dashed_line.xml b/app/src/main/res/drawable/dashed_line.xml new file mode 100644 index 0000000..9fc0ae0 --- /dev/null +++ b/app/src/main/res/drawable/dashed_line.xml @@ -0,0 +1,9 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_check.xml b/app/src/main/res/drawable/ic_check.xml new file mode 100644 index 0000000..efb34ea --- /dev/null +++ b/app/src/main/res/drawable/ic_check.xml @@ -0,0 +1,5 @@ + + + + diff --git a/app/src/main/res/drawable/ic_github.xml b/app/src/main/res/drawable/ic_github.xml new file mode 100644 index 0000000..c8fd210 --- /dev/null +++ b/app/src/main/res/drawable/ic_github.xml @@ -0,0 +1,4 @@ + + + diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 0000000..07d5da9 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_settings.xml b/app/src/main/res/drawable/ic_settings.xml new file mode 100644 index 0000000..6da10fa --- /dev/null +++ b/app/src/main/res/drawable/ic_settings.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/minus.png b/app/src/main/res/drawable/minus.png new file mode 100644 index 0000000..df8b24a Binary files /dev/null and b/app/src/main/res/drawable/minus.png differ diff --git a/app/src/main/res/drawable/rounded_background_for_btm.xml b/app/src/main/res/drawable/rounded_background_for_btm.xml new file mode 100644 index 0000000..47ad445 --- /dev/null +++ b/app/src/main/res/drawable/rounded_background_for_btm.xml @@ -0,0 +1,8 @@ + + + + + diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml new file mode 100644 index 0000000..5a9ca90 --- /dev/null +++ b/app/src/main/res/layout/activity_main.xml @@ -0,0 +1,211 @@ + + + + + + + + + + + + + + + + + + + +