diff options
16 files changed, 557 insertions, 9 deletions
| diff --git a/remoteExample/src/main/AndroidManifest.xml b/remoteExample/src/main/AndroidManifest.xml index 4e922e56..1d76db58 100644 --- a/remoteExample/src/main/AndroidManifest.xml +++ b/remoteExample/src/main/AndroidManifest.xml @@ -2,9 +2,19 @@  <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_launcher2" +        android:icon="@drawable/ic_launcher"          android:label="@string/app_name"          android:theme="@style/AppTheme" >          <activity 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/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/MainFragment.java b/remoteExample/src/main/java/de/blinkt/openvpn/remote/MainFragment.java index e14d7d3c..2ea37861 100644 --- a/remoteExample/src/main/java/de/blinkt/openvpn/remote/MainFragment.java +++ b/remoteExample/src/main/java/de/blinkt/openvpn/remote/MainFragment.java @@ -2,16 +2,320 @@ 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.util.AttributeSet; +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; -public class MainFragment extends Fragment {      @Override      public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { -        return inflater.inflate(R.layout.fragment_main,container,false); +        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.pngBinary files differ new file mode 100644 index 00000000..d4e4bdf6 --- /dev/null +++ b/remoteExample/src/main/res/drawable-hdpi/ic_launcher.png diff --git a/remoteExample/src/main/res/drawable-hdpi/ic_launcher2.png b/remoteExample/src/main/res/drawable-hdpi/ic_launcher2.pngBinary files differ deleted file mode 100644 index 55621cc1..00000000 --- a/remoteExample/src/main/res/drawable-hdpi/ic_launcher2.png +++ /dev/null diff --git a/remoteExample/src/main/res/drawable-mdpi/ic_launcher.png b/remoteExample/src/main/res/drawable-mdpi/ic_launcher.pngBinary files differ new file mode 100644 index 00000000..930cd9e7 --- /dev/null +++ b/remoteExample/src/main/res/drawable-mdpi/ic_launcher.png diff --git a/remoteExample/src/main/res/drawable-mdpi/ic_launcher2.png b/remoteExample/src/main/res/drawable-mdpi/ic_launcher2.pngBinary files differ deleted file mode 100644 index 11ec2068..00000000 --- a/remoteExample/src/main/res/drawable-mdpi/ic_launcher2.png +++ /dev/null diff --git a/remoteExample/src/main/res/drawable-xhdpi/ic_launcher.png b/remoteExample/src/main/res/drawable-xhdpi/ic_launcher.pngBinary files differ new file mode 100644 index 00000000..1fa27b61 --- /dev/null +++ b/remoteExample/src/main/res/drawable-xhdpi/ic_launcher.png diff --git a/remoteExample/src/main/res/drawable-xhdpi/ic_launcher2.png b/remoteExample/src/main/res/drawable-xhdpi/ic_launcher2.pngBinary files differ deleted file mode 100644 index 7c02b784..00000000 --- a/remoteExample/src/main/res/drawable-xhdpi/ic_launcher2.png +++ /dev/null diff --git a/remoteExample/src/main/res/drawable-xxhdpi/ic_launcher2.png b/remoteExample/src/main/res/drawable-xxhdpi/ic_launcher2.pngBinary files differ deleted file mode 100644 index 915d9144..00000000 --- a/remoteExample/src/main/res/drawable-xxhdpi/ic_launcher2.png +++ /dev/null diff --git a/remoteExample/src/main/res/layout/fragment_main.xml b/remoteExample/src/main/res/layout/fragment_main.xml index fef7793f..5069780c 100644 --- a/remoteExample/src/main/res/layout/fragment_main.xml +++ b/remoteExample/src/main/res/layout/fragment_main.xml @@ -6,11 +6,65 @@      android:paddingRight="@dimen/activity_horizontal_margin"      android:paddingTop="@dimen/activity_vertical_margin"      android:paddingBottom="@dimen/activity_vertical_margin" -    tools:context="de.blinkt.openvpn.remote.MainActivity$PlaceholderFragment"> +    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="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="Not now" +            android:visibility="visible" />      <TextView -        android:text="@string/hello_world" -        android:layout_width="wrap_content" -        android:layout_height="wrap_content" /> +            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" +            android: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="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="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="Start embedded profile" />  </RelativeLayout> diff --git a/remoteExample/src/main/res/values/strings.xml b/remoteExample/src/main/res/values/strings.xml index c1da58ca..a83b7642 100644 --- a/remoteExample/src/main/res/values/strings.xml +++ b/remoteExample/src/main/res/values/strings.xml @@ -1,8 +1,10 @@  <?xml version="1.0" encoding="utf-8"?>  <resources> -    <string name="app_name">My Module</string> +    <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> +  </resources> | 
