Commit ad0270b6 authored by Daniel Wolf's avatar Daniel Wolf
Browse files

Initial commit

parents
*.iml
.gradle
/local.properties
/.idea/workspace.xml
/.idea/libraries
.DS_Store
/build
/captures
.externalNativeBuild
[submodule "AndroidUtils"]
path = AndroidUtils
url = https://git.frostnerd.com/development/AndroidUtils.git
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<resourceExtensions />
<wildcardResourcePatterns>
<entry name="!?*.java" />
<entry name="!?*.form" />
<entry name="!?*.class" />
<entry name="!?*.groovy" />
<entry name="!?*.scala" />
<entry name="!?*.flex" />
<entry name="!?*.kt" />
<entry name="!?*.clj" />
<entry name="!?*.aj" />
</wildcardResourcePatterns>
<annotationProcessing>
<profile default="true" name="Default" enabled="false">
<processorPath useClasspath="true" />
</profile>
</annotationProcessing>
</component>
</project>
\ No newline at end of file
<component name="CopyrightManager">
<settings default="" />
</component>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding">
<file url="PROJECT" charset="UTF-8" />
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="GradleSettings">
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>
<option name="distributionType" value="DEFAULT_WRAPPED" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="modules">
<set>
<option value="$PROJECT_DIR$" />
<option value="$PROJECT_DIR$/AndroidUtils/library" />
<option value="$PROJECT_DIR$/app" />
</set>
</option>
<option name="resolveModulePerSourceSet" value="false" />
</GradleProjectSettings>
</option>
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="EntryPointsManager">
<entry_points version="2.0" />
</component>
<component name="NullableNotNullManager">
<option name="myDefaultNullable" value="android.support.annotation.Nullable" />
<option name="myDefaultNotNull" value="android.support.annotation.NonNull" />
<option name="myNullables">
<value>
<list size="4">
<item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.Nullable" />
<item index="1" class="java.lang.String" itemvalue="javax.annotation.Nullable" />
<item index="2" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.Nullable" />
<item index="3" class="java.lang.String" itemvalue="android.support.annotation.Nullable" />
</list>
</value>
</option>
<option name="myNotNulls">
<value>
<list size="4">
<item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.NotNull" />
<item index="1" class="java.lang.String" itemvalue="javax.annotation.Nonnull" />
<item index="2" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.NonNull" />
<item index="3" class="java.lang.String" itemvalue="android.support.annotation.NonNull" />
</list>
</value>
</option>
</component>
<component name="ProjectLevelVcsManager" settingsEditedManually="false">
<OptionsSetting value="true" id="Add" />
<OptionsSetting value="true" id="Remove" />
<OptionsSetting value="true" id="Checkout" />
<OptionsSetting value="true" id="Update" />
<OptionsSetting value="true" id="Status" />
<OptionsSetting value="true" id="Edit" />
<ConfirmationsSetting value="0" id="Add" />
<ConfirmationsSetting value="0" id="Remove" />
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="true" assert-keyword="true" jdk-15="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" />
</component>
<component name="ProjectType">
<option name="id" value="Android" />
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/DnsChanger.iml" filepath="$PROJECT_DIR$/DnsChanger.iml" />
<module fileurl="file://$PROJECT_DIR$/app/app.iml" filepath="$PROJECT_DIR$/app/app.iml" />
<module fileurl="file://$PROJECT_DIR$/AndroidUtils/library/library.iml" filepath="$PROJECT_DIR$/AndroidUtils/library/library.iml" />
</modules>
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RunConfigurationProducerService">
<option name="ignoredProducers">
<set>
<option value="org.jetbrains.plugins.gradle.execution.test.runner.AllInPackageGradleConfigurationProducer" />
<option value="org.jetbrains.plugins.gradle.execution.test.runner.TestClassGradleConfigurationProducer" />
<option value="org.jetbrains.plugins.gradle.execution.test.runner.TestMethodGradleConfigurationProducer" />
</set>
</option>
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>
\ No newline at end of file
AndroidUtils @ 0302f371
Subproject commit 0302f371ce34fe62ae3bd7831dccdf5c5b5bd66f
apply plugin: 'com.android.application'
android {
compileSdkVersion 25
buildToolsVersion "25.0.2"
defaultConfig {
applicationId "com.frostnerd.dnschanger"
minSdkVersion 16
targetSdkVersion 25
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
compile 'com.android.support:appcompat-v7:25.1.1'
testCompile 'junit:junit:4.12'
compile project(path: ':library')
}
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in E:\Dev\AndroidSDK/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# 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 *;
#}
package com.frostnerd.dnschanger;
import android.content.Context;
import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.junit.Assert.*;
/**
* Instrumentation test, which will execute on an Android device.
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
@RunWith(AndroidJUnit4.class)
public class ExampleInstrumentedTest {
@Test
public void useAppContext() throws Exception {
// Context of the app under test.
Context appContext = InstrumentationRegistry.getTargetContext();
assertEquals("com.frostnerd.dnschanger", appContext.getPackageName());
}
}
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.frostnerd.dnschanger">
<uses-permission android:name="android.permission.INTERNET" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service
android:name=".DNSVpnService"
android:enabled="true"
android:permission="android.permission.BIND_VPN_SERVICE">
<intent-filter>
<action android:name="android.net.VpnService" />
</intent-filter>
</service>
</application>
</manifest>
\ No newline at end of file
package com.frostnerd.dnschanger;
import android.content.Intent;
import android.net.VpnService;
import android.os.ParcelFileDescriptor;
import com.frostnerd.utils.preferences.Preferences;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.channels.DatagramChannel;
/**
* Copyright Daniel Wolf 2017
* All rights reserved.
* <p>
* development@frostnerd.com
*/
public class DNSVpnService extends VpnService {
private boolean run = true, isRunning = false;
private Thread thread;
private ParcelFileDescriptor tunnelInterface;
private Builder builder = new Builder();
@Override
public void onDestroy() {
run = false;
if(thread != null)thread.interrupt();
thread = null;
super.onDestroy();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (intent.getBooleanExtra("stop_vpn", false)) {
System.out.println("Stopping VPN");
if (thread != null) {
run = false;
thread.interrupt();
thread = null;
}
} else if(intent.getBooleanExtra("start_vpn", false)){
System.out.println("Starting VPN..");
if (thread != null) {
run = false;
thread.interrupt();
}
thread = new Thread(new Runnable() {
@Override
public void run() {
try {
String dns1 = Preferences.getString(DNSVpnService.this, "dns1", "8.8.8.8"),
dns2 = Preferences.getString(DNSVpnService.this, "dns1", "8.8.4.4");
tunnelInterface = builder.setSession("DnsChanger").addAddress("192.168.0.1", 24).addDnsServer(dns1).addDnsServer(dns2).establish();
DatagramChannel tunnel = DatagramChannel.open();
tunnel.connect(new InetSocketAddress("127.0.0.1", 8087));
protect(tunnel.socket());
isRunning = true;
System.out.println("VPN up and running");
try {
while(run){
Thread.sleep(100);
}
}catch(InterruptedException e2){
}
isRunning = false;
} catch (IOException e) {
}finally {
if(tunnelInterface != null) try {
tunnelInterface.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
});
run = true;
thread.start();
}
return super.onStartCommand(intent, flags, startId);
}
}
package com.frostnerd.dnschanger;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.media.Image;
import android.net.Uri;
import android.net.VpnService;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView;
import com.frostnerd.utils.design.MaterialEditText;
import com.frostnerd.utils.general.Utils;
import com.frostnerd.utils.preferences.Preferences;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import static com.frostnerd.utils.general.Utils.between;
public class MainActivity extends AppCompatActivity {
private Button startStopButton;
private boolean vpnRunning;
private MaterialEditText met_dns1, met_dns2;
private EditText dns1, dns2;
private static final HashMap<String, List<String>> defaultDNS = new HashMap<>();
private static final List<String> defaultDNSKeys;
private TextView connectionText;
private ImageView connectionImage;
private LinearLayout defaultDNSView;
private Button rate, info;
private ImageButton importButton;
static {
defaultDNS.put("Google DNS", Arrays.asList("8.8.8.8", "8.8.4.4"));
defaultDNS.put("OpenDNS", Arrays.asList("208.67.222.222", "208.67.220.220"));
defaultDNS.put("Level3", Arrays.asList("209.244.0.3", "209.244.0.4"));
defaultDNS.put("FreeDNS", Arrays.asList("37.235.1.174", "37.235.1.177"));
defaultDNS.put("Yandex DNS", Arrays.asList("77.88.8.8", "77.88.8.1"));
defaultDNS.put("Verisign", Arrays.asList("64.6.64.6", "64.6.65.6"));
defaultDNS.put("Alternate DNS", Arrays.asList("198.101.242.72", "23.253.163.53"));
defaultDNSKeys = new ArrayList<>(defaultDNS.keySet());
}
private void setIndicatorState(boolean vpnRunning) {
if (vpnRunning) {
int color = Color.parseColor("#43A047");
connectionText.setText(R.string.connected);
connectionImage.setImageResource(R.drawable.ic_thumb_up);
findViewById(R.id.activity_main).setBackgroundColor(Color.parseColor("#4CAF50"));
startStopButton.setBackgroundColor(color);
met_dns1.setCardColor(color);
met_dns1.setCardStrokeColor(color);
met_dns2.setCardColor(color);
met_dns2.setCardStrokeColor(color);
defaultDNSView.setBackgroundColor(color);
rate.setBackgroundColor(color);
info.setBackgroundColor(color);
importButton.setBackgroundColor(color);
} else {
int color = Color.parseColor("#42A5F5");
connectionText.setText(R.string.not_connected);
connectionImage.setImageResource(R.drawable.ic_thumb_down);
findViewById(R.id.activity_main).setBackgroundColor(Color.parseColor("#2196F3"));
startStopButton.setBackgroundColor(color);
met_dns1.setCardColor(color);
met_dns1.setCardStrokeColor(color);
met_dns2.setCardColor(color);
met_dns2.setCardStrokeColor(color);
defaultDNSView.setBackgroundColor(color);
rate.setBackgroundColor(color);
info.setBackgroundColor(color);
importButton.setBackgroundColor(color);
}
}
public void rateApp(View v) {
final String appPackageName = getPackageName();
try {
startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=" + appPackageName)));
} catch (android.content.ActivityNotFoundException e) {
startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("https://play.google.com/store/apps/details?id=" + appPackageName)));
}
}
public void openDNSInfoDialog(View v) {
new AlertDialog.Builder(this).setTitle(R.string.info_dns_button).setMessage(R.string.dns_info_text).setCancelable(true).setNeutralButton(R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
}
}).show();
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
met_dns1 = (MaterialEditText) findViewById(R.id.met_dns1);
met_dns2 = (MaterialEditText) findViewById(R.id.met_dns2);
dns1 = (EditText) findViewById(R.id.dns1);
dns2 = (EditText) findViewById(R.id.dns2);
connectionImage = (ImageView)findViewById(R.id.connection_status_image);
connectionText = (TextView)findViewById(R.id.connection_status_text);
defaultDNSView = (LinearLayout)findViewById(R.id.default_dns_view);
rate = (Button)findViewById(R.id.rate);
info = (Button)findViewById(R.id.dnsInfo);
importButton = (ImageButton)findViewById(R.id.default_dns_view_image);
dns1.setText(Preferences.getString(MainActivity.this, "dns1", "8.8.8.8"));
dns2.setText(Preferences.getString(MainActivity.this, "dns2", "8.8.4.4"));
startStopButton = (Button) findViewById(R.id.startStopButton);
startStopButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent i = VpnService.prepare(MainActivity.this);
if (i != null) startActivityForResult(i, 0);
else onActivityResult(0, RESULT_OK, null);
}
});
dns1.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
if (!Utils.isIP(s.toString())) {
met_dns1.setIndicatorState(MaterialEditText.IndicatorState.INCORRECT);
if(vpnRunning)stopVpn();
} else {
met_dns1.setIndicatorState(MaterialEditText.IndicatorState.UNDEFINED);
Preferences.put(MainActivity.this, "dns1", s.toString());
}
}
@Override
public void afterTextChanged(Editable s) {
}
});
dns2.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
if (!Utils.isIP(s.toString())) {
met_dns2.setIndicatorState(MaterialEditText.IndicatorState.INCORRECT);
if(vpnRunning)stopVpn();
} else {
met_dns2.setIndicatorState(MaterialEditText.IndicatorState.UNDEFINED);
Preferences.put(MainActivity.this, "dns2", s.toString());
}
}
@Override
public void afterTextChanged(Editable s) {
}
});
setIndicatorState(false);
}
public void openDefaultDNSDialog(View v) {
View layout = getLayoutInflater().inflate(R.layout.dialog_default_dns, null, false);
final ListView list = (ListView) layout.findViewById(R.id.defaultDnsDialogList);
list.setAdapter(new DefaultDNSAdapter());
list.setDividerHeight(0);
final AlertDialog dialog = new AlertDialog.Builder(this).setView(layout).setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
}
}).setTitle(R.string.default_dns_title).show();
list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
dialog.cancel();
List<String> ips = defaultDNS.get(defaultDNSKeys.get(position));
dns1.setText(ips.get(0));
dns2.setText(ips.get(1));
}
});
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == 0 && resultCode == RESULT_OK) {
if (!vpnRunning){
startVpn();
setIndicatorState(true);
}else{
stopVpn();
setIndicatorState(false);
}
}
super.onActivityResult(requestCode, resultCode, data);
}
private void startVpn() {
startService(new Intent(this, DNSVpnService.class).putExtra("start_vpn", true));
vpnRunning = true;
}
private void stopVpn() {
startService(new Intent(this, DNSVpnService.class).putExtra("stop_vpn", true));
stopService(new Intent(this, DNSVpnService.class));
vpnRunning = false;
}
private class DefaultDNSAdapter extends BaseAdapter {
@Override
public int getCount() {
return defaultDNS.size();
}
@Override