summaryrefslogtreecommitdiff
path: root/remoteExample
diff options
context:
space:
mode:
Diffstat (limited to 'remoteExample')
-rw-r--r--remoteExample/build.gradle32
-rw-r--r--remoteExample/src/main/AndroidManifest.xml31
-rw-r--r--remoteExample/src/main/aidl/de/blinkt/openvpn/api/APIVpnProfile.aidl3
-rw-r--r--remoteExample/src/main/aidl/de/blinkt/openvpn/api/IOpenVPNAPIService.aidl50
-rw-r--r--remoteExample/src/main/aidl/de/blinkt/openvpn/api/IOpenVPNStatusCallback.aidl13
-rw-r--r--remoteExample/src/main/assets/hd.conf61
-rw-r--r--remoteExample/src/main/ic_launcher2-web.pngbin0 -> 47072 bytes
-rw-r--r--remoteExample/src/main/java/de/blinkt/openvpn/api/APIVpnProfile.java51
-rw-r--r--remoteExample/src/main/java/de/blinkt/openvpn/remote/MainActivity.java51
-rw-r--r--remoteExample/src/main/java/de/blinkt/openvpn/remote/MainFragment.java321
-rw-r--r--remoteExample/src/main/res/drawable-hdpi/ic_launcher.pngbin0 -> 1447 bytes
-rw-r--r--remoteExample/src/main/res/drawable-mdpi/ic_launcher.pngbin0 -> 917 bytes
-rw-r--r--remoteExample/src/main/res/drawable-xhdpi/ic_launcher.pngbin0 -> 1984 bytes
-rw-r--r--remoteExample/src/main/res/layout/activity_main.xml7
-rw-r--r--remoteExample/src/main/res/layout/fragment_main.xml70
-rw-r--r--remoteExample/src/main/res/menu/main.xml9
-rw-r--r--remoteExample/src/main/res/values-w820dp/dimens.xml6
-rw-r--r--remoteExample/src/main/res/values/dimens.xml6
-rw-r--r--remoteExample/src/main/res/values/strings.xml15
-rw-r--r--remoteExample/src/main/res/values/styles.xml8
20 files changed, 734 insertions, 0 deletions
diff --git a/remoteExample/build.gradle b/remoteExample/build.gradle
new file mode 100644
index 00000000..59e37fbd
--- /dev/null
+++ b/remoteExample/build.gradle
@@ -0,0 +1,32 @@
+buildscript {
+ repositories {
+ mavenCentral()
+ }
+ dependencies {
+ classpath 'com.android.tools.build:gradle:0.9.+'
+ }
+}
+
+apply plugin: 'android'
+
+android {
+ compileSdkVersion 19
+ buildToolsVersion "19.0.3"
+
+ defaultConfig {
+ minSdkVersion 15
+ targetSdkVersion 19
+ versionCode 1
+ versionName "1.0"
+ }
+ buildTypes {
+ release {
+ runProguard false
+ proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
+ }
+ }
+}
+
+dependencies {
+ compile fileTree(dir: 'libs', include: ['*.jar', '*.aar'])
+}
diff --git a/remoteExample/src/main/AndroidManifest.xml b/remoteExample/src/main/AndroidManifest.xml
new file mode 100644
index 00000000..1d76db58
--- /dev/null
+++ b/remoteExample/src/main/AndroidManifest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="de.blinkt.openvpn.remote" >
+
+ <permission
+ android:name="de.blinkt.openvpn.REMOTE_API"
+ android:description="@string/permission_description"
+ android:label="Control OpenVPN"
+ android:permissionGroup="android.permission-group.NETWORK"
+ android:protectionLevel="dangerous" />
+
+ <uses-permission android:name="android.permission.INTERNET" />
+ <uses-permission android:name="de.blinkt.openvpn.REMOTE_API" />
+
+ <application
+ android:allowBackup="true"
+ android:icon="@drawable/ic_launcher"
+ android:label="@string/app_name"
+ android:theme="@style/AppTheme" >
+ <activity
+ android:name="de.blinkt.openvpn.remote.MainActivity"
+ android:label="@string/app_name" >
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+
+</manifest>
diff --git a/remoteExample/src/main/aidl/de/blinkt/openvpn/api/APIVpnProfile.aidl b/remoteExample/src/main/aidl/de/blinkt/openvpn/api/APIVpnProfile.aidl
new file mode 100644
index 00000000..f6799659
--- /dev/null
+++ b/remoteExample/src/main/aidl/de/blinkt/openvpn/api/APIVpnProfile.aidl
@@ -0,0 +1,3 @@
+package de.blinkt.openvpn.api;
+
+parcelable APIVpnProfile;
diff --git a/remoteExample/src/main/aidl/de/blinkt/openvpn/api/IOpenVPNAPIService.aidl b/remoteExample/src/main/aidl/de/blinkt/openvpn/api/IOpenVPNAPIService.aidl
new file mode 100644
index 00000000..794e3aad
--- /dev/null
+++ b/remoteExample/src/main/aidl/de/blinkt/openvpn/api/IOpenVPNAPIService.aidl
@@ -0,0 +1,50 @@
+// IOpenVPNAPIService.aidl
+package de.blinkt.openvpn.api;
+
+import de.blinkt.openvpn.api.APIVpnProfile;
+import de.blinkt.openvpn.api.IOpenVPNStatusCallback;
+
+import android.content.Intent;
+import android.os.ParcelFileDescriptor;
+
+interface IOpenVPNAPIService {
+ List<APIVpnProfile> getProfiles();
+
+ void startProfile (String profileUUID);
+
+ /** Use a profile with all certificates etc. embedded */
+ boolean addVPNProfile (String name, String config);
+
+ /** start a profile using an config */
+ void startVPN (String inlineconfig);
+
+ /** This permission framework is used to avoid confused deputy style attack to the VPN
+ * calling this will give null if the app is allowed to use the external API and an Intent
+ * that can be launched to request permissions otherwise */
+ Intent prepare (String packagename);
+
+ /** Used to trigger to the Android VPN permission dialog (VPNService.prepare()) in advance,
+ * if this return null OpenVPN for ANdroid already has the permissions otherwise you can start the returned Intent
+ * to let OpenVPN for Android request the permission */
+ Intent prepareVPNService ();
+
+ /* Disconnect the VPN */
+ void disconnect();
+
+ /* Pause the VPN (same as using the pause feature in the notifcation bar) */
+ void pause();
+
+ /* Resume the VPN (same as using the pause feature in the notifcation bar) */
+ void resume();
+
+ /**
+ * Registers to receive OpenVPN Status Updates
+ */
+ void registerStatusCallback(IOpenVPNStatusCallback cb);
+
+ /**
+ * Remove a previously registered callback interface.
+ */
+ void unregisterStatusCallback(IOpenVPNStatusCallback cb);
+
+} \ No newline at end of file
diff --git a/remoteExample/src/main/aidl/de/blinkt/openvpn/api/IOpenVPNStatusCallback.aidl b/remoteExample/src/main/aidl/de/blinkt/openvpn/api/IOpenVPNStatusCallback.aidl
new file mode 100644
index 00000000..1dfa1381
--- /dev/null
+++ b/remoteExample/src/main/aidl/de/blinkt/openvpn/api/IOpenVPNStatusCallback.aidl
@@ -0,0 +1,13 @@
+package de.blinkt.openvpn.api;
+
+/**
+ * Example of a callback interface used by IRemoteService to send
+ * synchronous notifications back to its clients. Note that this is a
+ * one-way interface so the server does not block waiting for the client.
+ */
+oneway interface IOpenVPNStatusCallback {
+ /**
+ * Called when the service has a new status for you.
+ */
+ void newStatus(String uuid, String state, String message, String level);
+}
diff --git a/remoteExample/src/main/assets/hd.conf b/remoteExample/src/main/assets/hd.conf
new file mode 100644
index 00000000..3dc917aa
--- /dev/null
+++ b/remoteExample/src/main/assets/hd.conf
@@ -0,0 +1,61 @@
+# This config does not work,
+# it only thought as demo to show starting a profile
+client
+
+proto tcp
+dev tun
+topology subnet
+
+remote openvpn.blinkt.de 2000
+tls-remote openvpn.blinkt.de
+
+<auth-user-pass>
+wronguser
+wrongpassword
+</auth-user-pass>
+
+comp-lzo
+<ca>
+-----BEGIN CERTIFICATE-----
+MIIHPTCCBSWgAwIBAgIBADANBgkqhkiG9w0BAQQFADB5MRAwDgYDVQQKEwdSb290
+IENBMR4wHAYDVQQLExVodHRwOi8vd3d3LmNhY2VydC5vcmcxIjAgBgNVBAMTGUNB
+IENlcnQgU2lnbmluZyBBdXRob3JpdHkxITAfBgkqhkiG9w0BCQEWEnN1cHBvcnRA
+Y2FjZXJ0Lm9yZzAeFw0wMzAzMzAxMjI5NDlaFw0zMzAzMjkxMjI5NDlaMHkxEDAO
+BgNVBAoTB1Jvb3QgQ0ExHjAcBgNVBAsTFWh0dHA6Ly93d3cuY2FjZXJ0Lm9yZzEi
+MCAGA1UEAxMZQ0EgQ2VydCBTaWduaW5nIEF1dGhvcml0eTEhMB8GCSqGSIb3DQEJ
+ARYSc3VwcG9ydEBjYWNlcnQub3JnMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC
+CgKCAgEAziLA4kZ97DYoB1CW8qAzQIxL8TtmPzHlawI229Z89vGIj053NgVBlfkJ
+8BLPRoZzYLdufujAWGSuzbCtRRcMY/pnCujW0r8+55jE8Ez64AO7NV1sId6eINm6
+zWYyN3L69wj1x81YyY7nDl7qPv4coRQKFWyGhFtkZip6qUtTefWIonvuLwphK42y
+fk1WpRPs6tqSnqxEQR5YYGUFZvjARL3LlPdCfgv3ZWiYUQXw8wWRBB0bF4LsyFe7
+w2t6iPGwcswlWyCR7BYCEo8y6RcYSNDHBS4CMEK4JZwFaz+qOqfrU0j36NK2B5jc
+G8Y0f3/JHIJ6BVgrCFvzOKKrF11myZjXnhCLotLddJr3cQxyYN/Nb5gznZY0dj4k
+epKwDpUeb+agRThHqtdB7Uq3EvbXG4OKDy7YCbZZ16oE/9KTfWgu3YtLq1i6L43q
+laegw1SJpfvbi1EinbLDvhG+LJGGi5Z4rSDTii8aP8bQUWWHIbEZAWV/RRyH9XzQ
+QUxPKZgh/TMfdQwEUfoZd9vUFBzugcMd9Zi3aQaRIt0AUMyBMawSB3s42mhb5ivU
+fslfrejrckzzAeVLIL+aplfKkQABi6F1ITe1Yw1nPkZPcCBnzsXWWdsC4PDSy826
+YreQQejdIOQpvGQpQsgi3Hia/0PsmBsJUUtaWsJx8cTLc6nloQsCAwEAAaOCAc4w
+ggHKMB0GA1UdDgQWBBQWtTIb1Mfz4OaO873SsDrusjkY0TCBowYDVR0jBIGbMIGY
+gBQWtTIb1Mfz4OaO873SsDrusjkY0aF9pHsweTEQMA4GA1UEChMHUm9vdCBDQTEe
+MBwGA1UECxMVaHR0cDovL3d3dy5jYWNlcnQub3JnMSIwIAYDVQQDExlDQSBDZXJ0
+IFNpZ25pbmcgQXV0aG9yaXR5MSEwHwYJKoZIhvcNAQkBFhJzdXBwb3J0QGNhY2Vy
+dC5vcmeCAQAwDwYDVR0TAQH/BAUwAwEB/zAyBgNVHR8EKzApMCegJaAjhiFodHRw
+czovL3d3dy5jYWNlcnQub3JnL3Jldm9rZS5jcmwwMAYJYIZIAYb4QgEEBCMWIWh0
+dHBzOi8vd3d3LmNhY2VydC5vcmcvcmV2b2tlLmNybDA0BglghkgBhvhCAQgEJxYl
+aHR0cDovL3d3dy5jYWNlcnQub3JnL2luZGV4LnBocD9pZD0xMDBWBglghkgBhvhC
+AQ0ESRZHVG8gZ2V0IHlvdXIgb3duIGNlcnRpZmljYXRlIGZvciBGUkVFIGhlYWQg
+b3ZlciB0byBodHRwOi8vd3d3LmNhY2VydC5vcmcwDQYJKoZIhvcNAQEEBQADggIB
+ACjH7pyCArpcgBLKNQodgW+JapnM8mgPf6fhjViVPr3yBsOQWqy1YPaZQwGjiHCc
+nWKdpIevZ1gNMDY75q1I08t0AoZxPuIrA2jxNGJARjtT6ij0rPtmlVOKTV39O9lg
+18p5aTuxZZKmxoGCXJzN600BiqXfEVWqFcofN8CCmHBh22p8lqOOLlQ+TyGpkO/c
+gr/c6EWtTZBzCDyUZbAEmXZ/4rzCahWqlwQ3JNgelE5tDlG+1sSPypZt90Pf6DBl
+Jzt7u0NDY8RD97LsaMzhGY4i+5jhe1o+ATc7iwiwovOVThrLm82asduycPAtStvY
+sONvRUgzEv/+PDIqVPfE94rwiCPCR/5kenHA0R6mY7AHfqQv0wGP3J8rtsYIqQ+T
+SCX8Ev2fQtzzxD72V7DX3WnRBnc0CkvSyqD/HMaMyRa+xMwyN2hzXwj7UfdJUzYF
+CpUCTPJ5GhD22Dp1nPMd8aINcGeGG7MW9S/lpOt5hvk9C8JzC6WZrG/8Z7jlLwum
+GCSNe9FINSkYQKyTYOGWhlC0elnYjyELn8+CkcY7v2vcB5G5l1YjqrZslMZIBjzk
+zk6q5PYvCdxTby78dOs6Y5nCpqyJvKeyRKANihDjbPIky/qbn3BHLt4Ui9SyIAmW
+omTxJBzcoTWcFbLUvFUufQb1nA5V9FrWk9p2rSVzTMVD
+-----END CERTIFICATE-----
+</ca>
+verb 2
diff --git a/remoteExample/src/main/ic_launcher2-web.png b/remoteExample/src/main/ic_launcher2-web.png
new file mode 100644
index 00000000..5c63bc5e
--- /dev/null
+++ b/remoteExample/src/main/ic_launcher2-web.png
Binary files differ
diff --git a/remoteExample/src/main/java/de/blinkt/openvpn/api/APIVpnProfile.java b/remoteExample/src/main/java/de/blinkt/openvpn/api/APIVpnProfile.java
new file mode 100644
index 00000000..f5591764
--- /dev/null
+++ b/remoteExample/src/main/java/de/blinkt/openvpn/api/APIVpnProfile.java
@@ -0,0 +1,51 @@
+package de.blinkt.openvpn.api;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+public class APIVpnProfile implements Parcelable {
+
+ public final String mUUID;
+ public final String mName;
+ public final boolean mUserEditable;
+
+ public APIVpnProfile(Parcel in) {
+ mUUID = in.readString();
+ mName = in.readString();
+ mUserEditable = in.readInt() != 0;
+ }
+
+ public APIVpnProfile(String uuidString, String name, boolean userEditable) {
+ mUUID=uuidString;
+ mName = name;
+ mUserEditable=userEditable;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(mUUID);
+ dest.writeString(mName);
+ if(mUserEditable)
+ dest.writeInt(0);
+ else
+ dest.writeInt(1);
+ }
+
+ public static final Parcelable.Creator<APIVpnProfile> CREATOR
+ = new Parcelable.Creator<APIVpnProfile>() {
+ public APIVpnProfile createFromParcel(Parcel in) {
+ return new APIVpnProfile(in);
+ }
+
+ public APIVpnProfile[] newArray(int size) {
+ return new APIVpnProfile[size];
+ }
+ };
+
+
+}
diff --git a/remoteExample/src/main/java/de/blinkt/openvpn/remote/MainActivity.java b/remoteExample/src/main/java/de/blinkt/openvpn/remote/MainActivity.java
new file mode 100644
index 00000000..900383a2
--- /dev/null
+++ b/remoteExample/src/main/java/de/blinkt/openvpn/remote/MainActivity.java
@@ -0,0 +1,51 @@
+package de.blinkt.openvpn.remote;
+
+import android.app.Activity;
+import android.app.ActionBar;
+import android.app.Fragment;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
+import android.os.Build;
+
+public class MainActivity extends Activity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_main);
+
+ if (savedInstanceState == null) {
+ getFragmentManager().beginTransaction()
+ .add(R.id.container, new MainFragment())
+ .commit();
+ }
+ }
+
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+
+ // Inflate the menu; this adds items to the action bar if it is present.
+ getMenuInflater().inflate(R.menu.main, menu);
+ return true;
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ // Handle action bar item clicks here. The action bar will
+ // automatically handle clicks on the Home/Up button, so long
+ // as you specify a parent activity in AndroidManifest.xml.
+ int id = item.getItemId();
+ if (id == R.id.action_settings) {
+ return true;
+ }
+ return super.onOptionsItemSelected(item);
+ }
+
+
+
+}
diff --git a/remoteExample/src/main/java/de/blinkt/openvpn/remote/MainFragment.java b/remoteExample/src/main/java/de/blinkt/openvpn/remote/MainFragment.java
new file mode 100644
index 00000000..2ea37861
--- /dev/null
+++ b/remoteExample/src/main/java/de/blinkt/openvpn/remote/MainFragment.java
@@ -0,0 +1,321 @@
+package de.blinkt.openvpn.remote;
+
+import android.app.Activity;
+import android.app.Fragment;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.RemoteException;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.TextView;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.lang.reflect.InvocationTargetException;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.net.UnknownHostException;
+import java.util.List;
+
+import de.blinkt.openvpn.api.APIVpnProfile;
+import de.blinkt.openvpn.api.IOpenVPNAPIService;
+import de.blinkt.openvpn.api.IOpenVPNStatusCallback;
+
+public class MainFragment extends Fragment implements View.OnClickListener, Handler.Callback {
+
+ private TextView mHelloWorld;
+ private Button mStartVpn;
+ private TextView mMyIp;
+ private TextView mStatus;
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+ View v = inflater.inflate(R.layout.fragment_main, container, false);
+ v.findViewById(R.id.disconnect).setOnClickListener(this);
+ v.findViewById(R.id.getMyIP).setOnClickListener(this);
+ v.findViewById(R.id.startembedded).setOnClickListener(this);
+ mHelloWorld = (TextView) v.findViewById(R.id.helloworld);
+ mStartVpn = (Button) v.findViewById(R.id.startVPN);
+ mStatus = (TextView) v.findViewById(R.id.status);
+ mMyIp = (TextView) v.findViewById(R.id.MyIpText);
+
+
+ return v;
+
+ }
+
+ private static final int MSG_UPDATE_STATE = 0;
+ private static final int MSG_UPDATE_MYIP = 1;
+ private static final int START_PROFILE_EMBEDDED = 2;
+ private static final int START_PROFILE_BYUUID = 3;
+ private static final int ICS_OPENVPN_PERMISSION = 7;
+
+ protected IOpenVPNAPIService mService=null;
+ private Handler mHandler;
+
+
+
+
+ private void startEmbeddedProfile()
+ {
+ try {
+ InputStream conf = getActivity().getAssets().open("test.conf");
+ InputStreamReader isr = new InputStreamReader(conf);
+ BufferedReader br = new BufferedReader(isr);
+ String config="";
+ String line;
+ while(true) {
+ line = br.readLine();
+ if(line == null)
+ break;
+ config += line + "\n";
+ }
+ br.readLine();
+
+ // mService.addVPNProfile("test", config);
+ mService.startVPN(config);
+ } catch (IOException e) {
+ e.printStackTrace();
+ } catch (RemoteException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public void onStart() {
+ super.onStart();
+ mHandler = new Handler(this);
+ bindService();
+ }
+
+
+ private IOpenVPNStatusCallback mCallback = new IOpenVPNStatusCallback.Stub() {
+ /**
+ * This is called by the remote service regularly to tell us about
+ * new values. Note that IPC calls are dispatched through a thread
+ * pool running in each process, so the code executing here will
+ * NOT be running in our main thread like most other things -- so,
+ * to update the UI, we need to use a Handler to hop over there.
+ */
+
+ @Override
+ public void newStatus(String uuid, String state, String message, String level)
+ throws RemoteException {
+ Message msg = Message.obtain(mHandler, MSG_UPDATE_STATE, state + "|" + message);
+ msg.sendToTarget();
+
+ }
+
+ };
+
+
+ /**
+ * Class for interacting with the main interface of the service.
+ */
+ private ServiceConnection mConnection = new ServiceConnection() {
+ public void onServiceConnected(ComponentName className,
+ IBinder service) {
+ // This is called when the connection with the service has been
+ // established, giving us the service object we can use to
+ // interact with the service. We are communicating with our
+ // service through an IDL interface, so get a client-side
+ // representation of that from the raw service object.
+
+ mService = IOpenVPNAPIService.Stub.asInterface(service);
+
+ try {
+ // Request permission to use the API
+ Intent i = mService.prepare(getActivity().getPackageName());
+ if (i!=null) {
+ startActivityForResult(i, ICS_OPENVPN_PERMISSION);
+ } else {
+ onActivityResult(ICS_OPENVPN_PERMISSION, Activity.RESULT_OK,null);
+ }
+
+ } catch (RemoteException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+
+ public void onServiceDisconnected(ComponentName className) {
+ // This is called when the connection with the service has been
+ // unexpectedly disconnected -- that is, its process crashed.
+ mService = null;
+
+ }
+ };
+ private String mStartUUID=null;
+
+ private void bindService() {
+ getActivity().bindService(new Intent(IOpenVPNAPIService.class.getName()),
+ mConnection, Context.BIND_AUTO_CREATE);
+ }
+
+ protected void listVPNs() {
+
+ try {
+ List<APIVpnProfile> list = mService.getProfiles();
+ String all="List:";
+ for(APIVpnProfile vp:list) {
+ all = all + vp.mName + ":" + vp.mUUID + "\n";
+ }
+
+ if(list.size()> 0) {
+ Button b= mStartVpn;
+ b.setOnClickListener(this);
+ b.setVisibility(View.VISIBLE);
+ b.setText(list.get(0).mName);
+ mStartUUID = list.get(0).mUUID;
+ }
+
+
+
+ mHelloWorld.setText(all);
+
+ } catch (RemoteException e) {
+ // TODO Auto-generated catch block
+ mHelloWorld.setText(e.getMessage());
+ }
+ }
+
+ private void unbindService() {
+ getActivity().unbindService(mConnection);
+ }
+
+ @Override
+ public void onStop() {
+ super.onStop();
+ unbindService();
+ }
+
+ @Override
+ public void onClick(View v) {
+ switch (v.getId()) {
+ case R.id.startVPN:
+ try {
+ prepareStartProfile(START_PROFILE_BYUUID);
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ }
+ break;
+ case R.id.disconnect:
+ try {
+ mService.disconnect();
+ } catch (RemoteException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ break;
+ case R.id.getMyIP:
+
+ // Socket handling is not allowed on main thread
+ new Thread() {
+
+ @Override
+ public void run() {
+ try {
+ String myip = getMyOwnIP();
+ Message msg = Message.obtain(mHandler,MSG_UPDATE_MYIP,myip);
+ msg.sendToTarget();
+ } catch (Exception e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+
+ }
+ }.start();
+
+ break;
+ case R.id.startembedded:
+ try {
+ prepareStartProfile(START_PROFILE_EMBEDDED);
+ } catch (RemoteException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ break;
+ default:
+ break;
+ }
+
+ }
+
+ private void prepareStartProfile(int requestCode) throws RemoteException {
+ Intent requestpermission = mService.prepareVPNService();
+ if(requestpermission == null) {
+ onActivityResult(requestCode, Activity.RESULT_OK, null);
+ } else {
+ // Have to call an external Activity since services cannot used onActivityResult
+ startActivityForResult(requestpermission, requestCode);
+ }
+ }
+
+ public void onActivityResult(int requestCode, int resultCode, Intent data) {
+ if (resultCode == Activity.RESULT_OK) {
+ if(requestCode==START_PROFILE_EMBEDDED)
+ startEmbeddedProfile();
+ if(requestCode==START_PROFILE_BYUUID)
+ try {
+ mService.startProfile(mStartUUID);
+ } catch (RemoteException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ if (requestCode == ICS_OPENVPN_PERMISSION) {
+ listVPNs();
+ try {
+ mService.registerStatusCallback(mCallback);
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ }
+
+ }
+ }
+ };
+
+ String getMyOwnIP() throws UnknownHostException, IOException, RemoteException,
+ IllegalArgumentException, IllegalAccessException, InvocationTargetException, NoSuchMethodException
+ {
+ String resp="";
+ Socket client = new Socket();
+ // Setting Keep Alive forces creation of the underlying socket, otherwise getFD returns -1
+ client.setKeepAlive(true);
+
+
+ client.connect(new InetSocketAddress("v4address.com", 23),20000);
+ client.shutdownOutput();
+ BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream()));
+ while (true) {
+ String line = in.readLine();
+ if( line == null)
+ return resp;
+ resp+=line;
+ }
+
+ }
+
+
+
+ @Override
+ public boolean handleMessage(Message msg) {
+ if(msg.what == MSG_UPDATE_STATE) {
+ mStatus.setText((CharSequence) msg.obj);
+ } else if (msg.what == MSG_UPDATE_MYIP) {
+
+ mMyIp.setText((CharSequence) msg.obj);
+ }
+ return true;
+ }
+} \ No newline at end of file
diff --git a/remoteExample/src/main/res/drawable-hdpi/ic_launcher.png b/remoteExample/src/main/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 00000000..d4e4bdf6
--- /dev/null
+++ b/remoteExample/src/main/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/remoteExample/src/main/res/drawable-mdpi/ic_launcher.png b/remoteExample/src/main/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 00000000..930cd9e7
--- /dev/null
+++ b/remoteExample/src/main/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/remoteExample/src/main/res/drawable-xhdpi/ic_launcher.png b/remoteExample/src/main/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 00000000..1fa27b61
--- /dev/null
+++ b/remoteExample/src/main/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/remoteExample/src/main/res/layout/activity_main.xml b/remoteExample/src/main/res/layout/activity_main.xml
new file mode 100644
index 00000000..42dd4dfb
--- /dev/null
+++ b/remoteExample/src/main/res/layout/activity_main.xml
@@ -0,0 +1,7 @@
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:id="@+id/container"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ tools:context="de.blinkt.openvpn.remote.MainActivity"
+ tools:ignore="MergeRootFrame" />
diff --git a/remoteExample/src/main/res/layout/fragment_main.xml b/remoteExample/src/main/res/layout/fragment_main.xml
new file mode 100644
index 00000000..e4fa019d
--- /dev/null
+++ b/remoteExample/src/main/res/layout/fragment_main.xml
@@ -0,0 +1,70 @@
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:paddingLeft="@dimen/activity_horizontal_margin"
+ android:paddingRight="@dimen/activity_horizontal_margin"
+ android:paddingTop="@dimen/activity_vertical_margin"
+ android:paddingBottom="@dimen/activity_vertical_margin"
+ tools:context="de.blinkt.openvpn.remote.MainFragment">
+
+
+ <TextView
+ android:id="@+id/status"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignLeft="@+id/helloworld"
+ android:layout_alignParentTop="true"
+ android:text="@string/no_status_yet" />
+
+ <Button
+ android:id="@+id/startVPN"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignRight="@+id/helloworld"
+ android:layout_below="@+id/helloworld"
+ android:text="@string/no_now"
+ android:visibility="visible" />
+
+ <TextView
+ android:id="@+id/helloworld"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentLeft="true"
+ android:layout_centerVertical="true"
+ android:text="@string/hello_world" />
+
+ <TextView
+ android:id="@+id/MyIpText"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_above="@+id/helloworld"
+ android:layout_alignParentLeft="true"
+ tools:text="TextView" />
+
+ <Button
+ android:id="@+id/getMyIP"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentLeft="true"
+ android:layout_below="@+id/startVPN"
+ android:text="@string/show_my_ip" />
+
+ <Button
+ android:id="@+id/disconnect"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignBottom="@+id/startVPN"
+ android:layout_toRightOf="@+id/startVPN"
+ android:text="@string/disconnect" />
+
+ <Button
+ android:id="@+id/startembedded"
+ style="?android:attr/buttonStyleSmall"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentLeft="true"
+ android:layout_below="@+id/getMyIP"
+ android:text="@string/start_embedded" />
+
+</RelativeLayout>
diff --git a/remoteExample/src/main/res/menu/main.xml b/remoteExample/src/main/res/menu/main.xml
new file mode 100644
index 00000000..f732c1b4
--- /dev/null
+++ b/remoteExample/src/main/res/menu/main.xml
@@ -0,0 +1,9 @@
+<menu xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ tools:context="de.blinkt.openvpn.remote.MainActivity" >
+
+ <item android:id="@+id/action_settings"
+ android:title="@string/action_settings"
+ android:orderInCategory="100"
+ android:showAsAction="never" />
+</menu>
diff --git a/remoteExample/src/main/res/values-w820dp/dimens.xml b/remoteExample/src/main/res/values-w820dp/dimens.xml
new file mode 100644
index 00000000..63fc8164
--- /dev/null
+++ b/remoteExample/src/main/res/values-w820dp/dimens.xml
@@ -0,0 +1,6 @@
+<resources>
+ <!-- Example customization of dimensions originally defined in res/values/dimens.xml
+ (such as screen margins) for screens with more than 820dp of available width. This
+ would include 7" and 10" devices in landscape (~960dp and ~1280dp respectively). -->
+ <dimen name="activity_horizontal_margin">64dp</dimen>
+</resources>
diff --git a/remoteExample/src/main/res/values/dimens.xml b/remoteExample/src/main/res/values/dimens.xml
new file mode 100644
index 00000000..a0171a70
--- /dev/null
+++ b/remoteExample/src/main/res/values/dimens.xml
@@ -0,0 +1,6 @@
+<resources>
+ <!-- Default screen margins, per the Android Design guidelines. -->
+ <dimen name="activity_horizontal_margin">16dp</dimen>
+ <dimen name="activity_vertical_margin">16dp</dimen>
+
+ </resources>
diff --git a/remoteExample/src/main/res/values/strings.xml b/remoteExample/src/main/res/values/strings.xml
new file mode 100644
index 00000000..bbaee226
--- /dev/null
+++ b/remoteExample/src/main/res/values/strings.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <string name="app_name">OpenVPN Remote</string>
+ <string name="hello_world">Hello world!</string>
+ <string name="action_settings">Settings</string>
+ <string name="permission_description">Allows another app to control OpenVPN</string>
+ <string name="no_status_yet">No Status yet</string>
+ <string name="no_now">Not now</string>
+ <string name="show_my_ip">Show my IP</string>
+ <string name="disconnect">Disconnect</string>
+ <string name="start_embedded">Start embedded profile</string>
+
+
+</resources>
diff --git a/remoteExample/src/main/res/values/styles.xml b/remoteExample/src/main/res/values/styles.xml
new file mode 100644
index 00000000..ff6c9d2c
--- /dev/null
+++ b/remoteExample/src/main/res/values/styles.xml
@@ -0,0 +1,8 @@
+<resources>
+
+ <!-- Base application theme. -->
+ <style name="AppTheme" parent="android:Theme.Holo.Light.DarkActionBar">
+ <!-- Customize your theme here. -->
+ </style>
+
+</resources>