Merge branch 'master' of github.com:DanielPollithy/flashwifi

This commit is contained in:
gosticks 2018-01-24 23:42:54 +01:00
commit bb3d1de716
47 changed files with 2923 additions and 670 deletions

View File

@ -2,6 +2,7 @@
## What is this?
[WiFiota](https://tobywoerthle.github.io/flashWiFiSite/)
## ToDos

View File

@ -5,8 +5,8 @@ android {
buildToolsVersion '26.0.2'
defaultConfig {
applicationId "jenny.daniel.wifip2p"
minSdkVersion 22
targetSdkVersion 22
minSdkVersion 23
targetSdkVersion 23
multiDexEnabled = true
versionCode 1
versionName "1.0"
@ -48,5 +48,6 @@ dependencies {
compile 'com.github.kenglxn.QRGen:android:2.4.0'
compile 'me.dm7.barcodescanner:zxing:1.9.8'
compile 'pl.droidsonroids.gif:android-gif-drawable:1.2.10'
compile 'com.google.api-client:google-api-client:1.23.0'
testCompile 'junit:junit:4.12'
}

View File

@ -1,8 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.flashwifi.wifip2p">
<uses-sdk android:minSdkVersion="22" />
<uses-sdk android:minSdkVersion="23" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
@ -14,6 +15,10 @@
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission-sdk-23 android:name="android.permission.WRITE_SETTINGS" />
<uses-permission
android:name="android.permission.PACKAGE_USAGE_STATS"
tools:ignore="ProtectedPermissions"/>
<application

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

View File

@ -0,0 +1,20 @@
package com.flashwifi.wifip2p;
/**
* Created by daniel on 23.01.18.
*/
public class Constants {
public interface ACTION {
public static String MAIN_ACTION = "com.flashwifi.wifip2p.service.main";
public static String PREV_ACTION = "com.flashwifi.wifip2p.service.prev";
public static String PLAY_ACTION = "com.flashwifi.wifip2p.service.play";
public static String NEXT_ACTION = "com.flashwifi.wifip2p.service.next";
public static String STARTFOREGROUND_ACTION = "com.flashwifi.wifip2p.start_foreground_service";
public static String STOPFOREGROUND_ACTION = "com.flashwifi.wifip2p.sop_foreground_service";
}
public interface NOTIFICATION_ID {
public static int FOREGROUND_SERVICE = 101;
}
}

View File

@ -15,7 +15,7 @@ import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import com.flashwifi.wifip2p.iotaAPI.Requests.WalletAddressAndBalanceChecker;
import com.flashwifi.wifip2p.iotaAPI.Requests.WalletBalanceChecker;
import net.glxn.qrgen.android.QRCode;
@ -45,7 +45,7 @@ public class FundWalletFragment extends Fragment {
private Handler mHandler;
private static Boolean transactionInProgress = false;
private WalletAddressAndBalanceChecker addressAndBalanceChecker;
private WalletBalanceChecker addressAndBalanceChecker;
public FundWalletFragment() {
// Required empty public constructor
@ -84,19 +84,19 @@ public class FundWalletFragment extends Fragment {
hideLoadingGIF();
transactionInProgress = false;
if(returnStatus == "noError"){
balanceTextView.setText(balance + " i");
if(returnStatus.equals("noError")){
balanceTextView.setText(balance);
addressTextView.setText(depositAddress);
createAddressQRCode(depositAddress);
makeToastFundWalletFragment("Balance and address updated");
}
else if (returnStatus == "hostError"){
else if (returnStatus.equals("hostError")){
makeToastFundWalletFragment("Unable to reach host (node)");
}
else if (returnStatus == "addressError"){
else if (returnStatus.equals("addressError")){
makeToastFundWalletFragment("Error getting address");
}
else if (returnStatus == "balanceError"){
else if (returnStatus.equals("balanceError")){
makeToastFundWalletFragment("Error getting balance. May not be able to resolve host/node");
}
else{
@ -191,7 +191,7 @@ public class FundWalletFragment extends Fragment {
private void getBalance(){
transactionInProgress = true;
addressAndBalanceChecker = new WalletAddressAndBalanceChecker(getActivity(),getActivity().getString(R.string.preference_file_key),seed, mHandler,FUND_WALLET,true);
addressAndBalanceChecker = new WalletBalanceChecker(getActivity(),getActivity().getString(R.string.preference_file_key),seed, mHandler,FUND_WALLET,true);
addressAndBalanceChecker.execute();
}

View File

@ -1,17 +1,27 @@
package com.flashwifi.wifip2p;
import android.Manifest;
import android.app.AppOpsManager;
import android.app.FragmentManager;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Build;
import android.provider.Settings;
import android.support.design.widget.Snackbar;
import android.support.v4.app.ActivityCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.Gravity;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
import com.flashwifi.wifip2p.iotaFlashWrapper.Example;
import com.flashwifi.wifip2p.iotaFlashWrapper.IotaFlashBridge;
@ -71,6 +81,21 @@ public class HomeActivity extends AppCompatActivity {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
ActivityCompat.requestPermissions(HomeActivity.this,
new String[]{
Manifest.permission.ACCESS_WIFI_STATE,
Manifest.permission.CHANGE_WIFI_STATE,
Manifest.permission.CHANGE_NETWORK_STATE,
Manifest.permission.INTERNET,
Manifest.permission.ACCESS_NETWORK_STATE,
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.READ_PHONE_STATE,
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.CAMERA
},
1);
// iotalibflash
String iotaflash = readFile("iotaflash");
String iotaflashhelper = readFile("iotaflashhelper");
@ -87,6 +112,55 @@ public class HomeActivity extends AppCompatActivity {
}
}
@Override
public void onRequestPermissionsResult(int requestCode,
String permissions[], int[] grantResults) {
switch (requestCode) {
case 1: {
// If request is cancelled, the result arrays are empty.
int i = 0;
if (grantResults.length > 0) {
boolean ok = true;
for (int grantResult: grantResults) {
if (grantResult != PackageManager.PERMISSION_GRANTED) {
ok = false;
Log.d(TAG, "onRequestPermissionsResult: denied: " + permissions[i]);
}
i++;
}
if (ok) {
Toast.makeText(HomeActivity.this, "Permissions granted", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(HomeActivity.this, "Permissions denied", Toast.LENGTH_SHORT).show();
}
AppOpsManager appOps = (AppOpsManager) getSystemService(Context.APP_OPS_SERVICE);
int mode = appOps.checkOpNoThrow(AppOpsManager.OPSTR_GET_USAGE_STATS,
android.os.Process.myUid(), getPackageName());
if (mode != AppOpsManager.MODE_ALLOWED) {
Intent intent = new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS);
startActivity(intent);
}
int mode2 = appOps.checkOpNoThrow(AppOpsManager.OPSTR_WRITE_SETTINGS,
android.os.Process.myUid(), getPackageName());
if (mode2 != AppOpsManager.MODE_ALLOWED) {
Intent intent = new Intent(Settings.ACTION_MANAGE_WRITE_SETTINGS);
startActivity(intent);
}
} else {
// permission denied, boo! Disable the
// functionality that depends on this permission.
Toast.makeText(HomeActivity.this, "Permission denied to read your External storage", Toast.LENGTH_SHORT).show();
}
}
// other 'case' lines to check for other
// permissions this app might request
}
}
private void setProgressBar(int percentage) {
ProgressBar prog = (ProgressBar) findViewById(R.id.progressbar);
prog.setProgress(percentage);
@ -137,7 +211,10 @@ public class HomeActivity extends AppCompatActivity {
} else {
final EditText field = (EditText) findViewById(R.id.password);
field.setText("");
Snackbar.make(view, getString(R.string.wrong_password), Snackbar.LENGTH_LONG).setAction("Action", null).show();
Toast toast= Toast.makeText(getApplicationContext(),
getString(R.string.wrong_password), Toast.LENGTH_SHORT);
toast.setGravity(Gravity.TOP|Gravity.CENTER_HORIZONTAL, 0, 0);
toast.show();
}
}
@ -177,9 +254,17 @@ public class HomeActivity extends AppCompatActivity {
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(final View view) {
setProgressBar(50);
String password = new_password_field.getText().toString();
storeNewSeed(seed, password);
if (new_password_field.getText().toString().length() > 0) {
setProgressBar(50);
String password = new_password_field.getText().toString();
storeNewSeed(seed, password);
} else {
Toast toast= Toast.makeText(getApplicationContext(),
"No blank password allowed", Toast.LENGTH_SHORT);
toast.setGravity(Gravity.TOP|Gravity.CENTER_HORIZONTAL, 0, 0);
toast.show();
}
}
});
}

View File

@ -19,6 +19,7 @@ import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.ToggleButton;
@ -33,8 +34,6 @@ public class HotspotFragment extends Fragment {
private int numberConnectedPeers = 0;
WiFiDirectBroadcastService mService;
boolean mBound = false;
BroadcastReceiver updateUIReceiver;
public HotspotFragment() {
@ -72,33 +71,34 @@ public class HotspotFragment extends Fragment {
private void updateUi(Intent intent) {
Log.d(TAG, "updateUi: Got some network data into the hotspot fragment");
String numberAvailableDevices = Integer.toString(mService.getArrayList().size());
String numberAvailableDevices = Integer.toString(getmService().getArrayList().size());
TextView text = (TextView) getActivity().findViewById(R.id.numberPeers);
text.setVisibility(View.VISIBLE);
text.setText(String.format("%s peers", numberAvailableDevices));
final View activity_view = getActivity().findViewById(R.id.drawer_layout);
//if (intent.hasExtra("what") && intent.getExtras().getString("what", "").equals("connectivity_changed")) {
NetworkInfo network_info = mService.getNetwork_info();
WifiP2pInfo p2p_info = mService.getP2p_info();
WifiP2pGroup wifiP2pGroup = mService.getP2p_group();
NetworkInfo network_info = getmService().getNetwork_info();
WifiP2pInfo p2p_info = getmService().getP2p_info();
WifiP2pGroup wifiP2pGroup = getmService().getP2p_group();
//if (intent.hasExtra("currentDeviceConnected")) {
if (intent.hasExtra("currentDeviceConnected")) {
//String macAddress = intent.getExtras().getString("currentDeviceConnected");
if (network_info.getState() == NetworkInfo.State.CONNECTED) {
// ToDo: look for the other device and make sure we are only two
if (p2p_info.isGroupOwner) {
Snackbar.make(activity_view, "You are the group owner", Snackbar.LENGTH_LONG).setAction("Action", null).show();
mService.startNegotiationServer(false, null);
getmService().startNegotiationServer(false, null);
} else {
InetAddress groupOwnerAddress = p2p_info.groupOwnerAddress;
Snackbar.make(activity_view, "You are only a member of the group", Snackbar.LENGTH_LONG).setAction("Action", null).show();
mService.startNegotiationClient(groupOwnerAddress, false, null);
getmService().startNegotiationClient(groupOwnerAddress, false, null);
}
}
//}
}
@ -109,29 +109,58 @@ public class HotspotFragment extends Fragment {
@Override
public void onStop() {
super.onStop();
getActivity().unbindService(mConnection);
getActivity().unregisterReceiver(updateUIReceiver);
mBound = false;
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
initFragment();
}
@Override
public void onResume() {
super.onResume();
initFragment();
}
public WiFiDirectBroadcastService getmService() {
MainActivity act = (MainActivity) getActivity();
return act.getmService();
}
private void initFragment(){
IntentFilter filter = new IntentFilter();
filter.addAction("com.flashwifi.wifip2p.update_ui");
filter.addAction("com.flashwifi.wifip2p.start_roaming");
filter.addAction("com.flashwifi.wifip2p.stop_roaming");
updateUIReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
updateUi(intent);
if (getActivity() == null) {
Log.d(TAG, "onReceive: getActivity is null");
return;
}
if (intent.getAction().equals("com.flashwifi.wifip2p.start_roaming")) {
String mac = intent.getStringExtra("peer_mac_address");
ToggleButton toggle = (ToggleButton) getActivity().findViewById(R.id.startAPButton);
toggle.setChecked(false);
ProgressBar progressBar = (ProgressBar) getActivity().findViewById(R.id.progressbarAP);
progressBar.setVisibility(View.INVISIBLE);
} else if (intent.getAction().equals("com.flashwifi.wifip2p.stop_roaming")) {
ToggleButton toggle = (ToggleButton) getActivity().findViewById(R.id.startAPButton);
toggle.setChecked(false);
ProgressBar progressBar = (ProgressBar) getActivity().findViewById(R.id.progressbarAP);
progressBar.setVisibility(View.INVISIBLE);
} else {
updateUi(intent);
}
}
};
getActivity().registerReceiver(updateUIReceiver, filter);
// Bind to Service
Intent intent = new Intent(getActivity(), WiFiDirectBroadcastService.class);
getActivity().bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
getActivity().registerReceiver(updateUIReceiver, filter);
initUI();
@ -157,36 +186,25 @@ public class HotspotFragment extends Fragment {
// ToDo: Move this to a async task
//boolean status = (isNetworkConnected() && isInternetAvailable());
}
private boolean isNetworkConnected() {
ConnectivityManager cm = (ConnectivityManager) getActivity().getSystemService(Context.CONNECTIVITY_SERVICE);
return cm.getActiveNetworkInfo() != null;
}
public boolean isInternetAvailable() {
try {
InetAddress ipAddr = InetAddress.getByName("google.com");
return !ipAddr.getHostAddress().equals("");
} catch (Exception e) {
return false;
}
}
private void startDiscovery() {
final View activity_view = getActivity().findViewById(R.id.drawer_layout);
if (mBound) {
mService.setInRoleConsumer(false);
mService.setInRoleHotspot(true);
mService.getPeerList(new WifiP2pManager.ActionListener() {
if (getmService() != null) {
getmService().setInRoleConsumer(false);
getmService().setInRoleHotspot(true);
getmService().getPeerList(new WifiP2pManager.ActionListener() {
@Override
public void onSuccess() {
// show progress wheel
ProgressBar progressBar = (ProgressBar) getActivity().findViewById(R.id.progressbarAP);
progressBar.setVisibility(View.VISIBLE);
}
@Override
public void onFailure(int reasonCode) {
Snackbar.make(activity_view, "Aaaargh :( Searching problem!", Snackbar.LENGTH_LONG).setAction("Action", null).show();
ProgressBar progressBar = (ProgressBar) getActivity().findViewById(R.id.progressbarAP);
progressBar.setVisibility(View.INVISIBLE);
}
});
}
@ -195,20 +213,24 @@ public class HotspotFragment extends Fragment {
private void stopDiscovery() {
final View activity_view = getActivity().findViewById(R.id.drawer_layout);
if (mBound) {
mService.stopDiscovery(new WifiP2pManager.ActionListener() {
if (getmService() != null) {
getmService().stopDiscovery(new WifiP2pManager.ActionListener() {
@Override
public void onSuccess() {
mService.setInRoleConsumer(false);
mService.setInRoleHotspot(false);
getmService().setInRoleConsumer(false);
getmService().setInRoleHotspot(false);
Snackbar.make(activity_view, "Stopped Hotspot mode", Snackbar.LENGTH_LONG).setAction("Action", null).show();
ProgressBar progressBar = (ProgressBar) getActivity().findViewById(R.id.progressbarAP);
progressBar.setVisibility(View.INVISIBLE);
}
@Override
public void onFailure(int reasonCode) {
mService.setInRoleConsumer(false);
mService.setInRoleHotspot(false);
getmService().setInRoleConsumer(false);
getmService().setInRoleHotspot(false);
Snackbar.make(activity_view, "Aaaargh :( Problem stopping discovery", Snackbar.LENGTH_LONG).setAction("Action", null).show();
ProgressBar progressBar = (ProgressBar) getActivity().findViewById(R.id.progressbarAP);
progressBar.setVisibility(View.INVISIBLE);
}
});
}
@ -218,10 +240,16 @@ public class HotspotFragment extends Fragment {
private void initUI() {
final View activity_view = getActivity().findViewById(R.id.drawer_layout);
final ToggleButton button = (ToggleButton) getActivity().findViewById(R.id.startAPButton);
//button.setChecked(mService.isInRoleHotspot());
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (getmService() != null) {
if (!getmService().isSetup()) {
Snackbar.make(activity_view, "Please enable WiFi P2P", Snackbar.LENGTH_LONG).setAction("Action", null).show();
button.setChecked(false);
return;
}
}
if (button.isChecked()) {
startDiscovery();
Snackbar.make(activity_view, "Start Discovery Mode", Snackbar.LENGTH_LONG).setAction("Action", null).show();
@ -232,25 +260,4 @@ public class HotspotFragment extends Fragment {
}
});
}
/** Defines callbacks for service binding, passed to bindService() */
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName className,
IBinder service) {
// We've bound to LocalService, cast the IBinder and get LocalService instance
WiFiDirectBroadcastService.LocalBinder binder = (WiFiDirectBroadcastService.LocalBinder) service;
mService = binder.getService();
mBound = true;
final ToggleButton button = (ToggleButton) getActivity().findViewById(R.id.startAPButton);
button.setChecked(mService.isInRoleHotspot());
}
@Override
public void onServiceDisconnected(ComponentName arg0) {
mBound = false;
}
};
}

View File

@ -1,5 +1,6 @@
package com.flashwifi.wifip2p;
import android.app.ActivityManager;
import android.app.Fragment;
import android.app.FragmentManager;
import android.content.BroadcastReceiver;
@ -8,30 +9,42 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.content.SharedPreferences;
import android.net.wifi.p2p.WifiP2pManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.preference.PreferenceManager;
import android.support.design.widget.NavigationView;
import android.support.v4.view.GravityCompat;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.CompoundButton;
import android.view.View;
import android.widget.ListView;
import android.widget.Switch;
import android.widget.ProgressBar;
import android.widget.Toast;
import com.flashwifi.wifip2p.billing.Accountant;
import com.flashwifi.wifip2p.broadcast.WiFiDirectBroadcastService;
import com.flashwifi.wifip2p.iotaAPI.Requests.WalletBalanceChecker;
public class MainActivity extends AppCompatActivity
implements NavigationView.OnNavigationItemSelectedListener
{
private static final String TAG = "MainAct";
private String password;
private String seed;
private static final int PREF_UPDATE = 2;
private static final int BALANCE_RETRIEVE_TASK_COMPLETE = 1;
private Handler balanceHandler;
private DrawerLayout mDrawerLayout;
private ListView mDrawerList;
@ -46,22 +59,75 @@ public class MainActivity extends AppCompatActivity
private void subscribeToBroadcasts() {
IntentFilter filter = new IntentFilter();
filter.addAction("com.flashwifi.wifip2p.start_roaming");
filter.addAction("com.flashwifi.wifip2p.stop_roaming");
updateUIReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
try {
// hide progress bar
ProgressBar progressConnection = (ProgressBar) findViewById(R.id.progressConnection);
progressConnection.setVisibility(View.VISIBLE);
} catch (Exception e) {
}
if (intent.getAction().equals("com.flashwifi.wifip2p.start_roaming")) {
startRoamingView(intent.getStringExtra("peer_mac_address"),
intent.getStringExtra("ssid"),
intent.getStringExtra("key"));
} else if (intent.getAction().equals("com.flashwifi.wifip2p.stop_roaming")) {
Log.d(TAG, "onReceive: Reset billing state");
}
}
};
registerReceiver(updateUIReceiver, filter);
}
public boolean isTheServiceRunning() {
return isMyServiceRunning(WiFiDirectBroadcastService.class);
}
private boolean isMyServiceRunning(Class<?> serviceClass) {
ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
if (serviceClass.getName().equals(service.service.getClassName())) {
return true;
}
}
return false;
}
@Override
protected void onPause() {
super.onPause();
//unbindWifiBroadcast();
unsubscribeFromBroadcast();
}
private void unbindWifiBroadcast() {
try {unregisterReceiver(updateUIReceiver);
unbindService(mConnection);
}
catch(IllegalArgumentException e) {
}
}
@Override
protected void onResume() {
super.onResume();
initEverything();
}
private void unsubscribeFromBroadcast() {
try {
unregisterReceiver(updateUIReceiver);
updateUIReceiver = null;
} catch (Exception e){
}
}
private void initUi() {
final Switch switch_ = (Switch) findViewById(R.id.wifiSwitch);
/*final Switch switch_ = (Switch) findViewById(R.id.wifiSwitch);
switch_.setOnCheckedChangeListener(new Switch.OnCheckedChangeListener() {
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (isChecked) {
@ -75,16 +141,27 @@ public class MainActivity extends AppCompatActivity
mService.disableService();
}
}
});
});*/
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
// get the secrets from the login screen
Intent intent = getIntent();
password = intent.getStringExtra("password");
seed = intent.getStringExtra("seed");
setBalanceHandler();
updateBalance();
Accountant.getInstance().setSeed(seed);
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
@ -94,25 +171,46 @@ public class MainActivity extends AppCompatActivity
NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
navigationView.setNavigationItemSelectedListener(this);
// get the secrets from the login screen
Intent intent = getIntent();
password = intent.getStringExtra("password");
seed = intent.getStringExtra("seed");
PreferenceManager.setDefaultValues(this, R.xml.preferences, false);
beginForegroundService();
// Bind to Service
Intent intent2 = new Intent(this, WiFiDirectBroadcastService.class);
bindService(intent2, mConnection, Context.BIND_AUTO_CREATE);
}
public WiFiDirectBroadcastService getmService() {
if (mBound) {
return mService;
}
return null;
}
private void beginForegroundService() {
if (!isTheServiceRunning()) {
Intent startIntent = new Intent(MainActivity.this, WiFiDirectBroadcastService.class);
startIntent.setAction(Constants.ACTION.STARTFOREGROUND_ACTION);
startService(startIntent);
} else {
Log.d(TAG, "beginForegroundService: Service is already running");
}
}
private void initEverything() {
subscribeToBroadcasts();
initUi();
}
@Override
protected void onStop() {
super.onStop();
unregisterReceiver(updateUIReceiver);
unbindService(mConnection);
try {unregisterReceiver(updateUIReceiver);
unbindService(mConnection);
}
catch(IllegalArgumentException e) {
System.out.println(e);
}
}
@Override
@ -148,16 +246,16 @@ public class MainActivity extends AppCompatActivity
startSearchFragment();
} else if (id == R.id.nav_start) {
startHotspotFragment();
} else if (id == R.id.nav_itp) {
// } else if (id == R.id.nav_itp) {
//
} else if (id == R.id.nav_fund) {
startFundWalletFragment();
} else if (id == R.id.nav_withdraw) {
startWithdrawWalletFragment();
} else if (id == R.id.nav_conditions) {
// } else if (id == R.id.nav_conditions) {
} else if (id == R.id.nav_settings) {
startSettingsFragment();
}
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
@ -165,9 +263,37 @@ public class MainActivity extends AppCompatActivity
return true;
}
private boolean settingsAreReady(){
// check whether all necessary settings were set by the user
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
String[] intVariables = new String[]{
"edit_text_sell_min_minutes",
"edit_text_sell_price",
"edit_text_sell_max_minutes",
"edit_text_buy_price",
"edit_text_client_minutes"
};
String val;
for (String variable: intVariables) {
val = prefs.getString(variable, null);
if (val == null) {
Log.d("Variable not set: ", "settingsAreReady: " + variable);
return false;
}
}
return true;
}
private void updateBalance() {
WalletBalanceChecker balanceChecker = new WalletBalanceChecker(this,this.getString(R.string.preference_file_key),seed, balanceHandler,PREF_UPDATE,true);
balanceChecker.execute();
}
public void startSearchFragment() {
if (mBound && mService.isInRoleHotspot()) {
Toast.makeText(this, "Can't start search because you are hotspot", Toast.LENGTH_SHORT).show();
} else if (!settingsAreReady()) {
Toast.makeText(this, "Navigate to settings and assign all variables", Toast.LENGTH_SHORT).show();
} else {
Fragment fragment = new SearchFragment();
@ -181,6 +307,21 @@ public class MainActivity extends AppCompatActivity
}
private void startRoamingView(String macAddress, String ssid, String key){
// disable WiFi P2P
if (mBound) {
mService.stopDiscovery(new WifiP2pManager.ActionListener() {
@Override
public void onSuccess() {
Log.d("MainAct", "discovery stopped");
}
@Override
public void onFailure(int i) {
Log.d("MainAct", "discovery could not be stopped");
}
});
}
Intent intent = new Intent(this, RoamingActivity.class);
intent.putExtra("address", macAddress);
intent.putExtra("key", key);
@ -191,11 +332,11 @@ public class MainActivity extends AppCompatActivity
public void startHotspotFragment() {
if (mBound && mService.isInRoleConsumer()) {
Toast.makeText(this, "Can't start hotspot because you are searching", Toast.LENGTH_SHORT).show();
} else if (!settingsAreReady()) {
Toast.makeText(this, "Navigate to settings and assign all variables", Toast.LENGTH_SHORT).show();
} else {
Fragment fragment = new HotspotFragment();
Bundle args = new Bundle();
//args.putInt(PlanetFragment.ARG_PLANET_NUMBER, position);
//fragment.setArguments(args);
// Insert the fragment by replacing any existing fragment
FragmentManager fragmentManager = getFragmentManager();
@ -235,6 +376,20 @@ public class MainActivity extends AppCompatActivity
.commit();
}
private void startSettingsFragment() {
Fragment fragment = new SettingsFragment();
Bundle bundle = new Bundle();
bundle.putString("seed", seed);
fragment.setArguments(bundle);
fragment.setRetainInstance(true);
// Insert the fragment by replacing any existing fragment
FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction()
.replace(R.id.content_frame, fragment)
.commit();
}
@Override
public void onBackPressed() {
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
@ -270,6 +425,7 @@ public class MainActivity extends AppCompatActivity
WiFiDirectBroadcastService.LocalBinder binder = (WiFiDirectBroadcastService.LocalBinder) service;
mService = binder.getService();
mBound = true;
mService.enableService();
}
@Override
@ -277,4 +433,34 @@ public class MainActivity extends AppCompatActivity
mBound = false;
}
};
private void setBalanceHandler() {
//Handle post-asynctask activities
balanceHandler = new Handler(Looper.getMainLooper()) {
@Override
public void handleMessage(Message inputMessage) {
switch (inputMessage.what) {
case BALANCE_RETRIEVE_TASK_COMPLETE:
AddressBalanceTransfer addressBalanceTransfer = (AddressBalanceTransfer) inputMessage.obj;
String returnStatus = addressBalanceTransfer.getMessage();
if (returnStatus.equals("noError")) {
makeToastBalance("Balance updated");
} else if (returnStatus.equals("hostError")) {
makeToastBalance("Unable to reach host (node)");
} else if (returnStatus.equals("addressError")) {
makeToastBalance("Error getting address");
} else if (returnStatus.equals("balanceError")) {
makeToastBalance("Error getting balance. May not be able to resolve host/node");
} else {
makeToastBalance("Unknown error");
}
}
}
};
}
private void makeToastBalance(String message) {
Toast.makeText(this, message, Toast.LENGTH_SHORT).show();
}
}

View File

@ -1,5 +1,6 @@
package com.flashwifi.wifip2p;
import android.annotation.SuppressLint;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
@ -26,10 +27,12 @@ import android.widget.Button;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import com.flashwifi.wifip2p.billing.Accountant;
@ -37,6 +40,8 @@ import com.flashwifi.wifip2p.broadcast.WiFiDirectBroadcastService;
import com.flashwifi.wifip2p.datastore.PeerStore;
import com.flashwifi.wifip2p.protocol.NegotiationFinalization;
import org.w3c.dom.Text;
public class RoamingActivity extends AppCompatActivity {
private static final String TAG = "RoamingActivity";
@ -59,6 +64,7 @@ public class RoamingActivity extends AppCompatActivity {
private Button stopButton;
private boolean endRoamingFlag = false;
private boolean initiatedEnd;
@Override
protected void onStart() {
@ -93,20 +99,40 @@ public class RoamingActivity extends AppCompatActivity {
Log.d(TAG, "updateUi: message=" + message);
CheckBox apConnected = (CheckBox)findViewById(R.id.accessPointActive);
CheckBox flashEstablished = (CheckBox)findViewById(R.id.flashEstablished);
CheckBox channelFunded = (CheckBox)findViewById(R.id.channelFunded);
if (message.equals("AP SUCCESS")) {
apConnected.setChecked(true);
mService.resetBillingState();
// when the AP is setup we can start the server
startBillingProtocol();
} else if (message.equals("AP FAILED")) {
apConnected.setChecked(false);
Toast.makeText(getApplicationContext(), "Could not create Access point", Toast.LENGTH_LONG).show();
exitRoaming();
} else if (message.equals("AP STOPPED")) {
apConnected.setChecked(false);
} else if (message.equals("Channel established")) {
flashEstablished.setChecked(true);
} else if (message.equals("Start Channel funding")) {
// start the task
mService.fundChannel(address);
} else if (message.equals("Channel funded")) {
channelFunded.setChecked(true);
} else if (message.equals("Billing")) {
updateBillingCard();
} else if (message.equals("Channel closed")) {
exitRoaming();
if (mService.isInRoleHotspot()) {
showRetransferCard();
}
} else if (message.equals("Socket exception")) {
//Toast.makeText(getApplicationContext(), "Socket exception", Toast.LENGTH_LONG).show();
//exitRoaming();
} else if (message.equals("Exit")) {
Toast.makeText(getApplicationContext(), "Can't connect", Toast.LENGTH_LONG).show();
exitRoaming();
}
// ToDo: add a critical error that uses exitRoaming()
}
}
@ -118,25 +144,50 @@ public class RoamingActivity extends AppCompatActivity {
}
private void stopRoamingBroadcast() {
Intent local = new Intent();
local.setAction("com.flashwifi.wifip2p.stop_roaming");
this.sendBroadcast(local);
}
private void showRetransferCard() {
CardView cardView = (CardView) findViewById(R.id.card_view_tangle_attachment);
cardView.setVisibility(View.VISIBLE);
}
@SuppressLint("DefaultLocale")
private void updateBillingCard() {
CardView summaryView = (CardView) findViewById(R.id.card_view_overview);
if (summaryView.getVisibility() != View.VISIBLE) {
summaryView.setVisibility(View.VISIBLE);
}
String minutes = Integer.toString(Accountant.getInstance().getTotalDurance());
String megabytes_max = Integer.toString(Accountant.getInstance().getBookedMegabytes());
String megabytes_used = Integer.toString(Accountant.getInstance().getTotalMegabytes());
String iotas_transferred = Integer.toString(Accountant.getInstance().getTotalIotaPrice());
int minutes = Accountant.getInstance().getTotalDurance() / 60;
int minutes_max = Accountant.getInstance().getBookedMinutes();
int bytes_max = Accountant.getInstance().getBookedBytes();
int bytes_used = Accountant.getInstance().getTotalBytes();
int iotas_transferred = Accountant.getInstance().getTotalIotaPrice();
int iotas_max = Accountant.getInstance().getTotalIotaDeposit();
TextView summaryMinutes = (TextView) findViewById(R.id.summaryMinutes);
summaryMinutes.setText(String.format("%s minutes active", minutes));
summaryMinutes.setText(String.format("%d/%d minutes active", minutes, minutes_max));
TextView summaryMegabytes = (TextView) findViewById(R.id.summaryMegabytes);
summaryMegabytes.setText(String.format("%s/%s Megabytes roamed", megabytes_used, megabytes_max));
summaryMegabytes.setText(String.format("%d/%d Megabytes roamed", bytes_used, bytes_max));
TextView summaryIota = (TextView) findViewById(R.id.summaryIota);
summaryMegabytes.setText(String.format("%s Iota transferred", iotas_transferred));
summaryIota.setText(String.format("%d/%d Iota transferred", iotas_transferred, iotas_max));
ProgressBar progressMinutes = (ProgressBar) findViewById(R.id.progressbarDurance);
progressMinutes.setMax(minutes_max);
progressMinutes.setProgress(minutes);
ProgressBar progressMegabytes = (ProgressBar) findViewById(R.id.progressbarMegabytes);
progressMegabytes.setMax(bytes_max);
progressMegabytes.setProgress(bytes_used);
ProgressBar progressIota = (ProgressBar) findViewById(R.id.progressbarIota);
progressIota.setProgress(iotas_transferred);
progressIota.setMax(iotas_max);
}
@ -144,9 +195,9 @@ public class RoamingActivity extends AppCompatActivity {
private void startBillingProtocol() {
// setup the flash channel etc...
if (mService.isInRoleHotspot()) {
mService.startBillingServer();
mService.startBillingServer(address);
} else {
mService.startBillingClient();
mService.startBillingClient(address);
}
}
@ -166,6 +217,8 @@ public class RoamingActivity extends AppCompatActivity {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_roaming);
Accountant.getInstance().reset();
// Get the Intent that started this activity and extract the string
Intent intent = getIntent();
name = intent.getStringExtra("name");
@ -179,78 +232,12 @@ public class RoamingActivity extends AppCompatActivity {
}
private void cancelNotification() {
NotificationManager mNotificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationManager.cancel(1);
}
private void showNotification() {
// The id of the channel.
String CHANNEL_ID = "com.flashwifi.wifip2p.roaming_1";
String contentText = mService.isInRoleHotspot() ? "You are providing" : "You are consuming";
// ToDo: make this work on high API version
NotificationCompat.Builder mBuilder =
new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.icon_tethering_on)
.setContentTitle("IOTA HOTSPOT")
.setContentText(contentText);
// Creates an explicit intent for an Activity in your app
Intent resultIntent = new Intent(this, RoamingActivity.class);
// The stack builder object will contain an artificial back stack for the
// started Activity.
// This ensures that navigating backward from the Activity leads out of
// your app to the Home screen.
TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
// Adds the back stack for the Intent (but not the Intent itself)
stackBuilder.addParentStack(RoamingActivity.class);
// Adds the Intent that starts the Activity to the top of the stack
stackBuilder.addNextIntent(resultIntent);
PendingIntent resultPendingIntent =
stackBuilder.getPendingIntent(
0,
PendingIntent.FLAG_UPDATE_CURRENT
);
mBuilder.setContentIntent(resultPendingIntent);
NotificationManager mNotificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
// mNotificationId is a unique integer your app uses to identify the
// notification. For example, to cancel the notification, you can pass its ID
// number to NotificationManager.cancel().
mNotificationManager.notify(1, mBuilder.build());
}
private void initUI() {
//final EditText input = (EditText) findViewById(R.id.chat_input);
//Button button = (Button) findViewById(R.id.btn_send);
/*button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(final View view) {
addMessageRight(name, input.getText().toString());
// send the message to the peer
//mService.sendMessageToSocketServer(groupOwnerAddress, input.getText().toString());
}
});*/
/*FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(final View view) {
toggleHotspot();
}
});
listView = (ListView) findViewById(R.id.peer_list);
arrayList = new ArrayList<>();
listAdapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, arrayList);
listView.setAdapter(listAdapter);*/
}
/** Defines callbacks for service binding, passed to bindService() */
@ -294,10 +281,25 @@ public class RoamingActivity extends AppCompatActivity {
}
});
showNotification();
updateBillingCard();
// ToDo: update notification
//showNotification();
}
private void endRoaming() {
if (!initiatedEnd) {
initiatedEnd = true;
Accountant.getInstance().setCloseAfterwards(true);
// the next bill will send the close request
// meanwhile show a loading icon
ProgressBar stopProgressBar = (ProgressBar) findViewById(R.id.stopProgressBar);
stopProgressBar.setVisibility(View.VISIBLE);
}
}
private void exitRoaming() {
Accountant.getInstance().setCloseAfterwards(true);
endRoamingFlag = true;
cancelNotification();
if (mService.isInRoleHotspot()){
@ -306,7 +308,26 @@ public class RoamingActivity extends AppCompatActivity {
mService.disconnectAP();
}
mService.setRoaming(false);
mService.resetBillingState();
mService.setInRoleConsumer(false);
mService.setInRoleHotspot(false);
PeerStore.getInstance().clear();
// hide the spinner and the stop button
ProgressBar stopProgressBar = (ProgressBar) findViewById(R.id.stopProgressBar);
stopProgressBar.setVisibility(View.GONE);
Button stopButton = (Button) findViewById(R.id.stopRoamingButton);
stopButton.setVisibility(View.GONE);
TextView stopText = (TextView) findViewById(R.id.stopText);
stopText.setVisibility(View.VISIBLE);
stopRoamingBroadcast();
Toast.makeText(getApplicationContext(), "Press BACK now", Toast.LENGTH_LONG).show();
initiatedEnd = false;
//finish();
}
@Override

View File

@ -21,6 +21,7 @@ import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.Toast;
import android.widget.ToggleButton;
@ -32,6 +33,7 @@ import java.net.InetAddress;
import java.util.ArrayList;
import com.flashwifi.wifip2p.broadcast.WiFiDirectBroadcastService;
import com.flashwifi.wifip2p.iotaFlashWrapper.Main;
/**
* Fragment that appears in the "content_frame", shows a planet
@ -40,9 +42,7 @@ public class SearchFragment extends Fragment {
public final static String TAG = "SearchActivity";
WiFiDirectBroadcastService mService;
boolean mBound = false;
BroadcastReceiver updateUIReceiver;
BroadcastReceiver updateUIReceiver = null;
ArrayList<String> arrayList;
PeerListAdapter peerListAdapter;
@ -63,6 +63,14 @@ public class SearchFragment extends Fragment {
return rootView;
}
public WiFiDirectBroadcastService getmService() {
MainActivity act = (MainActivity) getActivity();
if (act != null) {
return act.getmService();
}
return null;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@ -86,8 +94,8 @@ public class SearchFragment extends Fragment {
}
private void updateList() {
peerListAdapter.notifyDataSetInvalidated();
peerListAdapter.clear();
// peerListAdapter.notifyDataSetInvalidated();
peerListAdapter.addAll(PeerStore.getInstance().getPeerArrayList());
peerListAdapter.notifyDataSetChanged();
}
@ -96,20 +104,22 @@ public class SearchFragment extends Fragment {
updateList();
String what = intent.getStringExtra("what");
Log.d(">>>>>>>>>>>>", "updateUi: " + what);
String message = intent.getStringExtra("message");
if (what == null) {
what = "";
}
if (what.equals("connectivity_changed")) {
if (what != null && what.equals("connectivity_changed")) {
String currentDeviceConnected = intent.getStringExtra("currentDeviceConnected");
startNegotiationProtocol(currentDeviceConnected);
}
if (message != null && message.equals("error")) {
String snd_message = intent.getStringExtra("snd_message");
Snackbar.make(view, snd_message, Snackbar.LENGTH_LONG).setAction("Action", null).show();
updateList();
}
}
private void startNegotiationProtocol(String macAddress){
WifiP2pInfo p2p_info = mService.getP2p_info();
WifiP2pInfo p2p_info = getmService().getP2p_info();
if (p2p_info.isGroupOwner) {
startNegotiationProtocolServer(macAddress);
@ -120,13 +130,13 @@ public class SearchFragment extends Fragment {
private void startNegotiationProtocolServer(String macAddress) {
// starts the server if necessary
WifiP2pInfo p2p_info = mService.getP2p_info();
NetworkInfo network_info = mService.getNetwork_info();
WifiP2pInfo p2p_info = getmService().getP2p_info();
NetworkInfo network_info = getmService().getNetwork_info();
if (network_info.getState() == NetworkInfo.State.CONNECTED) {
if (p2p_info.isGroupOwner) {
Log.d(TAG, "You are the group owner");
mService.startNegotiationServer(true, macAddress);
getmService().startNegotiationServer(true, macAddress);
Log.d(TAG, "SocketServer started");
}
}
@ -134,8 +144,8 @@ public class SearchFragment extends Fragment {
private void startNegotiationProtocolClient(String macAddress){
// starts the server if necessary
WifiP2pInfo p2p_info = mService.getP2p_info();
NetworkInfo network_info = mService.getNetwork_info();
WifiP2pInfo p2p_info = getmService().getP2p_info();
NetworkInfo network_info = getmService().getNetwork_info();
if (network_info.getState() == NetworkInfo.State.CONNECTED) {
if (!p2p_info.isGroupOwner) {
@ -143,40 +153,73 @@ public class SearchFragment extends Fragment {
// groupOwnerAddress = p2p_info.groupOwnerAddress;
InetAddress groupOwnerAddress = p2p_info.groupOwnerAddress;
Log.d(TAG, "Group owner address: " + p2p_info.groupOwnerAddress.getHostAddress());
mService.startNegotiationClient(groupOwnerAddress, true, macAddress);
getmService().startNegotiationClient(groupOwnerAddress, true, macAddress);
Log.d(TAG, "Client Socket started");
}
}
}
@Override
public void onPause() {
super.onPause();
if (updateUIReceiver != null) {
getActivity().unregisterReceiver(updateUIReceiver);
updateUIReceiver = null;
}
}
@Override
public void onStop() {
super.onStop();
getActivity().unbindService(mConnection);
getActivity().unregisterReceiver(updateUIReceiver);
mBound = false;
if (updateUIReceiver != null) {
getActivity().unregisterReceiver(updateUIReceiver);
updateUIReceiver = null;
}
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
initFragment();
}
@Override
public void onResume() {
super.onResume();
initFragment();
}
private void initFragment() {
IntentFilter filter = new IntentFilter();
filter.addAction("com.flashwifi.wifip2p.update_ui");
filter.addAction("com.flashwifi.wifip2p.start_roaming");
filter.addAction("com.flashwifi.wifip2p.stop_roaming");
updateUIReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (getActivity() == null) {
Log.d(TAG, "onReceive: getActivity is null");
return;
}
Log.d("", "onReceive: FRAGMENT HAT WAS");
updateUi(intent);
if (intent.getAction().equals("com.flashwifi.wifip2p.start_roaming")) {
String mac = intent.getStringExtra("peer_mac_address");
ToggleButton toggle = (ToggleButton) getActivity().findViewById(R.id.startSearchButton);
toggle.setChecked(false);
} else if (intent.getAction().equals("com.flashwifi.wifip2p.stop_roaming")) {
PeerStore.getInstance().clear();
busy = false;
ToggleButton toggle = (ToggleButton) getActivity().findViewById(R.id.startSearchButton);
toggle.setChecked(false);
} else {
updateUi(intent);
}
}
};
getActivity().registerReceiver(updateUIReceiver, filter);
// Bind to Service
Intent intent = new Intent(getActivity(), WiFiDirectBroadcastService.class);
getActivity().bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
view = getActivity().findViewById(R.id.fragment_view);
initUI();
@ -187,23 +230,24 @@ public class SearchFragment extends Fragment {
toolbar.setTitle("Discover Peers");
final ToggleButton toggle = (ToggleButton) getActivity().findViewById(R.id.startSearchButton);
//toggle.setChecked(mService.isInRoleConsumer());
toggle.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(final View view) {
if (!getmService().isSetup()) {
Snackbar.make(view, "Please enable WiFi P2P", Snackbar.LENGTH_LONG).setAction("Action", null).show();
toggle.setChecked(false);
return;
}
updateList();
if (toggle.isChecked()) {
if (mBound) {
mService.setInRoleHotspot(false);
mService.setInRoleConsumer(true);
startSearching();
}
getmService().setInRoleHotspot(false);
getmService().setInRoleConsumer(true);
startSearching();
} else {
if (mBound) {
mService.setInRoleHotspot(false);
mService.setInRoleConsumer(false);
stopSearching();
}
getmService().setInRoleHotspot(false);
getmService().setInRoleConsumer(false);
stopSearching();
}
}
});
@ -223,6 +267,11 @@ public class SearchFragment extends Fragment {
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
if (!busy) {
busy = true;
// show progress bar
ProgressBar progressConnection = (ProgressBar) getActivity().findViewById(R.id.progressConnection);
progressConnection.setVisibility(View.VISIBLE);
PeerInformation peer = PeerStore.getInstance().getPeerArrayList().get(i);
peer.setSelected(true);
@ -242,13 +291,13 @@ public class SearchFragment extends Fragment {
public void startChat(final String address, String name) {
mService.connect(address, new WifiP2pManager.ActionListener() {
getmService().connect(address, new WifiP2pManager.ActionListener() {
@Override
public void onSuccess() {
Toast.makeText(view.getContext(), "Connected to peer", Toast.LENGTH_SHORT).show();
// start the protocol
startNegotiationProtocol(address);
busy = false;
busy = true;
}
@Override
public void onFailure(int reason) {
@ -259,56 +308,31 @@ public class SearchFragment extends Fragment {
}
private void stopSearching() {
if (mBound) {
mService.stopDiscovery(new WifiP2pManager.ActionListener() {
@Override
public void onSuccess() {
Snackbar.make(view, "Stopped search", Snackbar.LENGTH_LONG).setAction("Action", null).show();
}
getmService().stopDiscovery(new WifiP2pManager.ActionListener() {
@Override
public void onSuccess() {
Snackbar.make(view, "Stopped search", Snackbar.LENGTH_LONG).setAction("Action", null).show();
}
@Override
public void onFailure(int reasonCode) {
Snackbar.make(view, "Aaaargh :( problem stopping search!", Snackbar.LENGTH_LONG).setAction("Action", null).show();
}
});
}
@Override
public void onFailure(int reasonCode) {
Snackbar.make(view, "Aaaargh :( problem stopping search!", Snackbar.LENGTH_LONG).setAction("Action", null).show();
}
});
}
public void startSearching() {
getmService().getPeerList(new WifiP2pManager.ActionListener() {
@Override
public void onSuccess() {
Snackbar.make(view, "Successfully searched for peers", Snackbar.LENGTH_LONG).setAction("Action", null).show();
}
if (mBound) {
mService.getPeerList(new WifiP2pManager.ActionListener() {
@Override
public void onSuccess() {
Snackbar.make(view, "Successfully searched for peers", Snackbar.LENGTH_LONG).setAction("Action", null).show();
}
@Override
public void onFailure(int reasonCode) {
Snackbar.make(view, "Aaaargh :( Peering problem!", Snackbar.LENGTH_LONG).setAction("Action", null).show();
}
});
@Override
public void onFailure(int reasonCode) {
Snackbar.make(view, "Aaaargh :( Peering problem!", Snackbar.LENGTH_LONG).setAction("Action", null).show();
}
});
}
}
/** Defines callbacks for service binding, passed to bindService() */
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName className,
IBinder service) {
// We've bound to LocalService, cast the IBinder and get LocalService instance
WiFiDirectBroadcastService.LocalBinder binder = (WiFiDirectBroadcastService.LocalBinder) service;
mService = binder.getService();
mBound = true;
final ToggleButton toggle = (ToggleButton) getActivity().findViewById(R.id.startSearchButton);
toggle.setChecked(mService.isInRoleConsumer());
}
@Override
public void onServiceDisconnected(ComponentName arg0) {
mBound = false;
}
};
}

View File

@ -0,0 +1,286 @@
package com.flashwifi.wifip2p;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.preference.Preference;
import android.preference.PreferenceCategory;
import android.preference.PreferenceFragment;
import android.preference.PreferenceManager;
import android.preference.PreferenceScreen;
import android.text.InputType;
import android.widget.EditText;
import android.widget.Toast;
import com.flashwifi.wifip2p.iotaAPI.Requests.WalletTestnetTokenGen;
import com.pddstudio.preferences.encrypted.EncryptedPreferences;
public class SettingsFragment extends PreferenceFragment implements SharedPreferences.OnSharedPreferenceChangeListener {
private String password = "";
private String seed = "";
private static final int TOKEN_TESTNET_RETRIEVE_TASK_COMPLETE = 0;
private static final int TOKEN_TESTNET_STATUS_UPDATE = 1;
private Handler mHandler;
private Preference testnetFundAddPref;
private Preference prefTestNetPrivate;
private PreferenceCategory prefCatIotaSettings;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Bundle bundle = this.getArguments();
if (bundle != null) {
seed = bundle.getString("seed");
}
// Load the preferences from an XML resource
addPreferencesFromResource(R.xml.preferences);
// Set version text
Preference version = findPreference("pref_key_reset_version");
String curTitle = version.getTitle().toString();
version.setTitle("Version: "+curTitle);
prefTestNetPrivate = findPreference("pref_key_switch_testnet_private");
prefCatIotaSettings = (PreferenceCategory) findPreference("pref_key_IOTA_settings");
SharedPreferences prefManager = PreferenceManager.getDefaultSharedPreferences(getActivity());
Boolean testnet = prefManager.getBoolean("pref_key_switch_testnet",false);
if(!testnet){
//Hide the testnet private switch
hideTestNetPref();
}
//Set change listener
getPreferenceScreen().getSharedPreferences()
.registerOnSharedPreferenceChangeListener(this);
//Handle post-asynctask activities of updating UI
mHandler = new Handler(Looper.getMainLooper()) {
@Override
public void handleMessage(Message inputMessage) {
String result = (String) inputMessage.obj;
switch (inputMessage.what) {
case TOKEN_TESTNET_STATUS_UPDATE:
if(result.equals("Sending")){
testnetFundAddPref.setSummary("Sending...");
}
break;
case TOKEN_TESTNET_RETRIEVE_TASK_COMPLETE:
if(result.equals("Sent")){
makeToastSettingsFragment("2000i generated and added to testnet wallet. Check balance.");
testnetFundAddPref.setSummary("2000i added");
}
else{
makeToastSettingsFragment(result);
testnetFundAddPref.setSummary(result);
}
break;
}
}
};
}
@Override
public void onResume() {
super.onResume();
if(testnetFundAddPref != null){
testnetFundAddPref.setSummary("");
}
}
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
switch(key){
case "pref_key_security":
//makeToastSettingsFragment("Security Changed");
break;
case "pref_key_network_timeout":
//makeToastSettingsFragment("Network Timeout Changed");
break;
case "pref_key_units":
makeToastSettingsFragment("Units Changed");
//makeToastSettingsFragment("Units Changed");
break;
case "pref_key_switch_testnet":
makeToastSettingsFragment("Testnet on/off Changed");
SharedPreferences prefManager = PreferenceManager.getDefaultSharedPreferences(getActivity());
Boolean testnet = prefManager.getBoolean("pref_key_switch_testnet",false);
if(testnet){
showTestNetPref();
}
else{
hideTestNetPref();
}
break;
case "edit_text_sell_price":
makeToastSettingsFragment("Hotspot Sell Price Changed");
break;
case "edit_text_sell_min_minutes":
makeToastSettingsFragment("Hotspot Min sell duration changed");
break;
case "edit_text_sell_max_minutes":
makeToastSettingsFragment("Hotspot Max sell duration changed");
break;
case "edit_text_buy_price":
makeToastSettingsFragment("Buy Price Changed");
break;
case "edit_text_client_minutes":
makeToastSettingsFragment("Client duration duration changed");
break;
}
}
@Override
public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
String key = preference.getKey();
switch (key) {
case "pref_key_reset_data_usage":
makeToastSettingsFragment( "Reset Data Usage");
break;
case "pref_key_testnet_fund_add":
SharedPreferences prefManager = PreferenceManager.getDefaultSharedPreferences(getActivity());
Boolean testnet = prefManager.getBoolean("pref_key_switch_testnet",false);
if(testnet){
testnetFundAddPref = preference;
testnetFundAddPref.setSummary("Generating...");
makeToastSettingsFragment("Testnet wallet token generation request sent.");
WalletTestnetTokenGen tokenGen = new WalletTestnetTokenGen(mHandler, getActivity(), getString(R.string.preference_file_key), seed);
tokenGen.execute();
}
else{
makeToastSettingsFragment("Please enable testnet first.");
}
break;
case "pref_key_reset_password":
makeToastSettingsFragment( "Reset Password");
askPassword();
break;
case "pref_key_reset_wallet":
makeToastSettingsFragment("Reset Wallet.");
break;
}
return super.onPreferenceTreeClick(preferenceScreen, preference);
}
private void askPassword() {
Context context = getActivity();
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setTitle("Enter current password");
final EditText input = new EditText(context);
input.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD);
builder.setView(input);
builder.setPositiveButton("OK", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
password = input.getText().toString();
updatePassword();
}
});
builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
password = "";
}
});
builder.show();
}
public void updatePassword(){
if(password.equals("")){
//Blank Password
makeToastSettingsFragment("Current password cannot be blank.");
return;
}
Context context = getActivity();
EncryptedPreferences encryptedPreferences = new EncryptedPreferences.Builder(context).withEncryptionPassword(password).build();
String seed = encryptedPreferences.getString(getString(R.string.encrypted_seed), null);
if (seed != null && context != null) {
//Correct password, re-store seed with new input password
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setTitle("Enter new password");
final EditText input = new EditText(context);
input.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD);
builder.setView(input);
builder.setPositiveButton("OK", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
String newPassword = input.getText().toString();
if(!newPassword.equals("")){
EncryptedPreferences encryptedPreferencesRemove = new EncryptedPreferences.Builder(context).withEncryptionPassword(password).build();
encryptedPreferencesRemove.edit().remove(getString(R.string.encrypted_seed)).apply();
EncryptedPreferences encryptedPreferencesUpdated = new EncryptedPreferences.Builder(context).withEncryptionPassword(newPassword).build();
encryptedPreferencesUpdated.edit().putString(getString(R.string.encrypted_seed), seed).apply();
password = "";
makeToastSettingsFragment("Password changed.");
}
else{
password = "";
makeToastSettingsFragment("New password cannot be blank.");
}
}
});
builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
password = "";
}
});
builder.show();
}
else{
//Wrong Password
makeToastSettingsFragment("Wrong Password. Please try again.");
}
}
private void makeToastSettingsFragment(String s) {
if(getActivity() != null){
Toast.makeText(getActivity(), s, Toast.LENGTH_SHORT).show();
}
}
private void hidePreference(String prefKey, String catKey){
Preference pref = findPreference(prefKey);
PreferenceCategory catPref = (PreferenceCategory) findPreference(catKey);
catPref.removePreference(pref);
}
private void showPreference(String prefKey, String catKey){
Preference pref = findPreference(prefKey);
PreferenceCategory catPref = (PreferenceCategory) findPreference(catKey);
catPref.addPreference(pref);
}
private void hideTestNetPref() {
prefCatIotaSettings.removePreference(prefTestNetPrivate);
}
private void showTestNetPref() {
prefCatIotaSettings.addPreference(prefTestNetPrivate);
}
}

View File

@ -20,7 +20,7 @@ import android.widget.ImageButton;
import android.widget.TextView;
import android.widget.Toast;
import com.flashwifi.wifip2p.iotaAPI.Requests.WalletAddressAndBalanceChecker;
import com.flashwifi.wifip2p.iotaAPI.Requests.WalletBalanceChecker;
import com.flashwifi.wifip2p.iotaAPI.Requests.WalletTransferRequest;
import jota.error.ArgumentException;
@ -47,7 +47,7 @@ public class WithdrawWalletFragment extends Fragment {
private EditText editTextAmount;
private EditText editTextMessage;
private EditText editTextTag;
private WalletAddressAndBalanceChecker addressAndBalanceChecker;
private WalletBalanceChecker addressAndBalanceChecker;
private GifImageView loadingGifImageView;
private SwipeRefreshLayout mSwipeRefreshLayout;
@ -94,22 +94,22 @@ public class WithdrawWalletFragment extends Fragment {
hideLoadingGIF();
transactionInProgress = false;
if(returnStatus == "noError"){
balanceTextView.setText(appWalletBalance + " i");
if(returnStatus.equals("noError")){
balanceTextView.setText(appWalletBalance);
makeToastFundWalletFragment("Balance updated");
}
else if (returnStatus == "noErrorNoUpdateMessage"){
balanceTextView.setText(appWalletBalance + " i");
else if (returnStatus.equals("noErrorNoUpdateMessage")){
balanceTextView.setText(appWalletBalance);
clearAllTransferValues();
makeFieldsEditable();
}
else if (returnStatus == "hostError"){
else if (returnStatus.equals("hostError")){
makeToastFundWalletFragment("Unable to reach host (node)");
}
else if (returnStatus == "addressError"){
else if (returnStatus.equals("addressError")){
makeToastFundWalletFragment("Error getting address");
}
else if (returnStatus == "balanceError"){
else if (returnStatus.equals("balanceError")){
makeToastFundWalletFragment("Error getting balance");
}
else{
@ -198,7 +198,7 @@ public class WithdrawWalletFragment extends Fragment {
private void getBalance(Boolean updateMessage) {
transactionInProgress = true;
addressAndBalanceChecker = new WalletAddressAndBalanceChecker(getActivity(),getActivity().getString(R.string.preference_file_key),appWalletSeed, mHandler,WITHDRAW_WALLET,updateMessage);
addressAndBalanceChecker = new WalletBalanceChecker(getActivity(),getActivity().getString(R.string.preference_file_key),appWalletSeed, mHandler,WITHDRAW_WALLET,updateMessage);
addressAndBalanceChecker.execute();
}

View File

@ -86,17 +86,20 @@ public class AccessPointTask extends AsyncTask<Object, Void, String> {
}
catch (IllegalArgumentException e) {
e.printStackTrace();
sendUpdateUIBroadcastWithMessage("AP FAILED");
}
catch (IllegalAccessException e) {
e.printStackTrace();
sendUpdateUIBroadcastWithMessage("AP FAILED");
}
catch (InvocationTargetException e) {
e.printStackTrace();
sendUpdateUIBroadcastWithMessage("AP FAILED");
}
}
}
if (!methodFound){
// ToDo: implement this
sendUpdateUIBroadcastWithMessage("AP FAILED");
//statusView.setText("Your phone's API does not contain setWifiApEnabled method to configure an access point");
}

View File

@ -8,15 +8,21 @@ public class Accountant {
private ArrayList<Bill> bills;
private int totalMegabytes;
private int totalBytes;
private int totalIotaPrice;
private int totalDurance;
private int bookedMegabytes;
private int bookedMinutes;
private int totalIotaDeposit;
private int timeoutMinutes;
private int iotaPerMegaByte;
private boolean closeAfterwards;
private long startTime;
private FlashChannelHelper flashChannelHelper;
private boolean closed = true;
private String seed;
public static Accountant getInstance() {
return ourInstance;
@ -25,19 +31,49 @@ public class Accountant {
private Accountant() {
}
public void start(int bookedMegabytes, int timeoutMinutes){
if (closed) {
bills = new ArrayList<Bill>();
this.bookedMegabytes = bookedMegabytes;
this.timeoutMinutes = timeoutMinutes;
totalMegabytes = 0;
totalIotaPrice = 0;
totalDurance = 0;
flashChannelHelper = new FlashChannelHelper();
closed = false;
public void start(int bookedMegabytes, int timeoutMinutes, int bookedMinutes, int totalIotaDeposit, int iotaPerMegaByte){
bills = new ArrayList<Bill>();
this.bookedMegabytes = bookedMegabytes;
this.timeoutMinutes = timeoutMinutes;
this.totalIotaDeposit = totalIotaDeposit;
this.iotaPerMegaByte = iotaPerMegaByte;
totalBytes = 0;
totalIotaPrice = 0;
totalDurance = 0;
flashChannelHelper = new FlashChannelHelper();
closeAfterwards = false;
startTime = System.currentTimeMillis() / 1000L;
this.bookedMinutes = bookedMinutes;
closed = false;
}
public long getLastTime() {
if (bills.isEmpty()) {
return startTime;
} else {
return bills.get(bills.size()-1).getTime();
}
}
public void reset() {
this.bookedMegabytes = 0;
this.timeoutMinutes = 0;
this.totalIotaDeposit = 0;
this.iotaPerMegaByte = 0;
totalBytes = 0;
totalIotaPrice = 0;
totalDurance = 0;
bookedMinutes = 0;
}
public boolean isCloseAfterwards() {
return closeAfterwards;
}
public void setCloseAfterwards(boolean closeAfterwards) {
this.closeAfterwards = closeAfterwards;
}
public int getNextBillNumber() {
return bills.size() + 1;
}
@ -54,22 +90,25 @@ public class Accountant {
// ToDo: check bill
totalMegabytes += b.getMegabytesUsed();
totalBytes += b.getBytesUsed();
totalIotaPrice += b.getPriceInIota();
totalDurance += b.getDuranceInMinutes();
totalDurance += b.getDuranceInSeconds();
// ToDo: apply transfer to flash channel
return true;
}
public Bill createBill(int megaByte, int priceInIota, int duranceMinutes){
public Bill createBill(int bytes){
if (!closed) {
Bill b = new Bill(getNextBillNumber(), totalDurance, duranceMinutes, megaByte, priceInIota);
long now = System.currentTimeMillis() / 1000L;
long duranceInSeconds = now - getLastTime();
int priceInIota = (int) (bytes * getIotaPerByte());
Bill b = new Bill(getNextBillNumber(), now, duranceInSeconds, bytes, priceInIota);
totalMegabytes += megaByte;
totalBytes += bytes;
totalIotaPrice += priceInIota;
totalDurance += duranceMinutes;
totalDurance += duranceInSeconds;
// 1) modify flash channel
applyTransferToFlashChannel(priceInIota);
@ -100,7 +139,11 @@ public class Accountant {
}
public int getTotalMegabytes() {
return totalMegabytes;
return totalBytes / (1024*1024);
}
public int getTotalBytes() {
return totalBytes / (1024*1024);
}
public int getTotalIotaPrice() {
@ -114,4 +157,36 @@ public class Accountant {
public int getBookedMegabytes() {
return bookedMegabytes;
}
public int getBookedBytes() {
return bookedMegabytes;
}
public int getTimeoutMinutes() {
return timeoutMinutes;
}
public int getBookedMinutes() {
return bookedMinutes;
}
public int getTotalIotaDeposit() {
return totalIotaDeposit;
}
public int getIotaPerMegaByte() {
return iotaPerMegaByte;
}
public double getIotaPerByte() {
return ((double)getIotaPerMegaByte()) / (1024.0d * 1024.0d);
}
public void setSeed(String seed) {
this.seed = seed;
}
public String getSeed() {
return seed;
}
}

View File

@ -3,18 +3,18 @@ package com.flashwifi.wifip2p.billing;
public class Bill {
private int index;
private int minuteStart;
private int duranceInMinutes = 1;
private int megabytesUsed;
private int bytesUsed;
private int priceInIota;
private long duranceInSeconds;
private long time;
private boolean acceptedByPeer;
public Bill(int index, int minuteStart, int duranceInMinutes, int megabytesUsed, int priceInIota) {
public Bill(int index, long time, long duranceInSeconds, int bytesUsed, int priceInIota) {
this.index = index;
this.minuteStart = minuteStart;
this.duranceInMinutes = duranceInMinutes;
this.megabytesUsed = megabytesUsed;
this.time = time;
this.duranceInSeconds = duranceInSeconds;
this.bytesUsed = bytesUsed;
this.priceInIota = priceInIota;
}
@ -30,19 +30,24 @@ public class Bill {
return index;
}
public int getMinuteStart() {
return minuteStart;
}
public int getDuranceInMinutes() {
return duranceInMinutes;
return (int) duranceInSeconds/60;
}
public int getMegabytesUsed() {
return megabytesUsed;
public int getDuranceInSeconds() {
return (int) duranceInSeconds;
}
public int getBytesUsed() {
return bytesUsed;
}
public int getPriceInIota() {
return priceInIota;
}
public long getTime() {
return time;
}
}

View File

@ -1,9 +1,12 @@
package com.flashwifi.wifip2p.billing;
import android.accounts.Account;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import com.flashwifi.wifip2p.datastore.PeerInformation;
import com.flashwifi.wifip2p.datastore.PeerStore;
import com.flashwifi.wifip2p.negotiation.SocketWrapper;
import com.flashwifi.wifip2p.protocol.BillMessage;
import com.flashwifi.wifip2p.protocol.BillMessageAnswer;
@ -11,6 +14,9 @@ import com.flashwifi.wifip2p.protocol.BillingCloseChannel;
import com.flashwifi.wifip2p.protocol.BillingCloseChannelAnswer;
import com.flashwifi.wifip2p.protocol.BillingOpenChannel;
import com.flashwifi.wifip2p.protocol.BillingOpenChannelAnswer;
import com.flashwifi.wifip2p.protocol.NegotiationFinalization;
import com.flashwifi.wifip2p.protocol.NegotiationOffer;
import com.flashwifi.wifip2p.protocol.NegotiationOfferAnswer;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
@ -30,11 +36,13 @@ import java.net.UnknownHostException;
public class BillingClient {
private static final String TAG = "BillingClient";
private final Gson gson;
private final String mac;
private State state = State.NOT_PAIRED;
private Socket socket;
private SocketWrapper socketWrapper;
private static final int PORT = 9199;
private static final int clientTimeoutMillis = 2 * 60 * 1000;
private static final int maxErrorCount = 5;
private BillingOpenChannel billingOpenChannel;
private BillingOpenChannelAnswer billingOpenChannelAnswer;
@ -49,15 +57,18 @@ public class BillingClient {
context.sendBroadcast(local);
}
public BillingClient(Context context){
public BillingClient(String mac, Context context){
this.context = context;
this.mac = mac;
gson = new GsonBuilder().create();
}
public void start(String serverIPAddress) {
while (state != State.CLOSED) {
int error_count = 0;
while (state != State.CLOSED && state != State.ERROR) {
try {
// create client socket that connects to server
socket = new Socket(serverIPAddress, PORT);
@ -74,17 +85,39 @@ public class BillingClient {
String hotspotStateLine = socketWrapper.getLineThrowing();
if (hotspotStateLine.contains("INITIAL") || hotspotStateLine.contains("NOT_PAIRED")) {
// ask the hotspot to open the flash channel
// get the negotiated data
NegotiationOffer offer = PeerStore.getInstance().getLatestNegotiationOffer(mac);
NegotiationOfferAnswer answer = PeerStore.getInstance().getLatestNegotiationOfferAnswer(mac);
NegotiationFinalization finalization = PeerStore.getInstance().getLatestFinalization(mac);
// get the necessary values
// ToDo: replace magic number with setting
int totalMegabytes = 100;
int treeDepth = 8;
String[] digests = new String[]{"1234", "2345", "3456"};
billingOpenChannel = new BillingOpenChannel(100, 100, "clientAddress", 8, digests, 20 * 60 * 1000);
int timeoutMinutesClient = 20 * 60 * 1000;
int iotaPerMegabyte = offer.getIotaPerMegabyte();
String clientRefundAddress = finalization.getClientRefundAddress();
int totalMinutes = answer.getDuranceInMinutes();
billingOpenChannel = new BillingOpenChannel(totalMegabytes, iotaPerMegabyte, clientRefundAddress, treeDepth, digests, timeoutMinutesClient, totalMinutes);
PeerStore.getInstance().setLatestBillingOpenChannel(mac, billingOpenChannel);
String billingOpenChannelString = gson.toJson(billingOpenChannel);
socketWrapper.sendLine(billingOpenChannelString);
// receive the hotspot details for the flash channel
String billingOpenChannelAnswerString = socketWrapper.getLineThrowing();
billingOpenChannelAnswer = gson.fromJson(billingOpenChannelAnswerString, BillingOpenChannelAnswer.class);
PeerStore.getInstance().setLatestBillingOpenChannelAnswer(mac, billingOpenChannelAnswer);
// now create the flash channel on our side
Accountant.getInstance().start(billingOpenChannel.getTotalMegabytes(), billingOpenChannel.getTimeoutMinutesClient());
Accountant.getInstance().start(billingOpenChannel.getTotalMegabytes(), billingOpenChannel.getTimeoutMinutesClient(), billingOpenChannel.getTotalMinutes(), billingOpenChannelAnswer.getClientDepositIota(),
billingOpenChannel.getIotaPerMegabyte());
sendUpdateUIBroadcastWithMessage("Channel established");
state = State.ROAMING;
// start the task to fund the channel
sendUpdateUIBroadcastWithMessage("Start Channel funding");
} else {
// what to do if the hotspot already created stuff and was in roaming mode
// ToDo: ^^^^^
@ -106,7 +139,7 @@ public class BillingClient {
// ToDo: flash object -> diff()
// ToDo: sign flash transaction
sendUpdateUIBroadcastWithMessage("Billing");
latestBillAnswer = new BillMessageAnswer("id", true, "", false);
latestBillAnswer = new BillMessageAnswer("id", true, "", Accountant.getInstance().isCloseAfterwards());
latestBillAnswerString = gson.toJson(latestBillAnswer);
socketWrapper.sendLine(latestBillAnswerString);
@ -128,16 +161,47 @@ public class BillingClient {
String billingCloseChannelAnswerString = gson.toJson(billingCloseChannelAnswer);
socketWrapper.sendLine(billingCloseChannelAnswerString);
sendUpdateUIBroadcastWithMessage("Channel closed");
state = State.CLOSED;
}
} catch (SocketException e) {
e.printStackTrace();
sendUpdateUIBroadcastWithMessage("Socket exception");
error_count++;
} catch (UnknownHostException e) {
sendUpdateUIBroadcastWithMessage("UnknownHostException exception");
e.printStackTrace();
error_count++;
} catch (IOException e) {
sendUpdateUIBroadcastWithMessage("IOException");
e.printStackTrace();
error_count++;
} finally {
if (socket != null) {
try {
socketWrapper.close();
} catch (IOException e) {
e.printStackTrace();
}
}
// sleep in finally case 5 seconds
try {
Thread.sleep(1000*5);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (error_count >= maxErrorCount) {
// stop trying to connect
Log.d(TAG, "start: error count too high");
state = State.ERROR;
sendUpdateUIBroadcastWithMessage("Exit");
}
}
}
}
@ -146,6 +210,7 @@ public class BillingClient {
NOT_PAIRED,
ROAMING,
CLOSE,
CLOSED
CLOSED,
ERROR
}
}

View File

@ -1,9 +1,16 @@
package com.flashwifi.wifip2p.billing;
import android.app.usage.NetworkStats;
import android.app.usage.NetworkStatsManager;
import android.content.Context;
import android.content.Intent;
import android.net.ConnectivityManager;
import android.net.wifi.WifiManager;
import android.os.RemoteException;
import android.text.format.Formatter;
import android.util.Log;
import com.flashwifi.wifip2p.datastore.PeerStore;
import com.flashwifi.wifip2p.negotiation.SocketWrapper;
import com.flashwifi.wifip2p.protocol.BillMessage;
import com.flashwifi.wifip2p.protocol.BillMessageAnswer;
@ -11,15 +18,21 @@ import com.flashwifi.wifip2p.protocol.BillingCloseChannel;
import com.flashwifi.wifip2p.protocol.BillingCloseChannelAnswer;
import com.flashwifi.wifip2p.protocol.BillingOpenChannel;
import com.flashwifi.wifip2p.protocol.BillingOpenChannelAnswer;
import com.flashwifi.wifip2p.protocol.NegotiationFinalization;
import com.flashwifi.wifip2p.protocol.NegotiationOffer;
import com.flashwifi.wifip2p.protocol.NegotiationOfferAnswer;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import java.io.IOException;
import java.math.BigDecimal;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.net.UnknownHostException;
import static android.content.Context.WIFI_SERVICE;
/**
* 1) This class keeps the socket connection alive.
* 2) It tracks the state of the communication.
@ -32,6 +45,10 @@ import java.net.UnknownHostException;
public class BillingServer {
private static final String TAG = "BillingServer";
private final Gson gson;
private final String mac;
private final String hotspotRefundAddress;
private final String channelRootAddress;
private final String[] digests;
private State state = State.NOT_PAIRED;
private ServerSocket serverSocket;
private Socket socket;
@ -40,6 +57,7 @@ public class BillingServer {
private static final int serverTimeoutMillis = 2 * 60 * 1000;
Context context;
NetworkStatsManager networkStatsManager;
private void sendUpdateUIBroadcastWithMessage(String message){
Intent local = new Intent();
@ -48,10 +66,33 @@ public class BillingServer {
context.sendBroadcast(local);
}
public BillingServer(int bookedMegabytes, int timeoutMinutes, Context context){
public BillingServer(String mac, Context context){
this.context = context;
Accountant.getInstance().start(bookedMegabytes,timeoutMinutes);
this.mac = mac;
// get the negotiated data
NegotiationOffer offer = PeerStore.getInstance().getLatestNegotiationOffer(mac);
NegotiationOfferAnswer answer = PeerStore.getInstance().getLatestNegotiationOfferAnswer(mac);
NegotiationFinalization finalization = PeerStore.getInstance().getLatestFinalization(mac);
// get the necessary values
// ToDo: replace magic number with setting
int totalMegabytes = 100;
int treeDepth = 8;
this.digests = new String[]{"1234", "2345", "3456"};
int timeoutMinutesServer = 20 * 60 * 1000;
this.hotspotRefundAddress = finalization.getHotspotRefundAddress();
this.channelRootAddress = finalization.getDepositAddressFlashChannel();
int iotaPerMegabyte = offer.getIotaPerMegabyte();
int iotaDepositClient = totalMegabytes * iotaPerMegabyte;
String clientRefundAddress = finalization.getClientRefundAddress();
int totalMinutes = answer.getDuranceInMinutes();
Accountant.getInstance().start(totalMegabytes, timeoutMinutesServer, totalMinutes, iotaDepositClient, iotaPerMegabyte);
gson = new GsonBuilder().create();
networkStatsManager = (NetworkStatsManager) context.getSystemService(Context.NETWORK_STATS_SERVICE);
}
public void start() throws IOException {
@ -59,6 +100,10 @@ public class BillingServer {
createDeadlineGuard();
// 1) create a socket
Log.d(TAG, "start: Billing server has been started");
// ToDo: receive end of roaming broadcast
while (state != State.CLOSED) {
try {
// create server socket
@ -86,11 +131,20 @@ public class BillingServer {
// receive the BillingOpenChannel message
String billingOpenChannelString = socketWrapper.getLineThrowing();
BillingOpenChannel billingOpenChannel = gson.fromJson(billingOpenChannelString, BillingOpenChannel.class);
PeerStore.getInstance().setLatestBillingOpenChannel(mac, billingOpenChannel);
// answer with billingOpenChannelAnswerString
// ToDo: create the flash channel
String[] myDigests = new String[]{"1234", "2345", "3456"};
BillingOpenChannelAnswer billingOpenChannelAnswer = new BillingOpenChannelAnswer(0, 0, "", "", myDigests);
BillingOpenChannelAnswer billingOpenChannelAnswer = new BillingOpenChannelAnswer(
Accountant.getInstance().getTotalIotaDeposit(),
Accountant.getInstance().getTotalIotaDeposit(),
hotspotRefundAddress,
channelRootAddress,
digests);
PeerStore.getInstance().setLatestBillingOpenChannelAnswer(mac, billingOpenChannelAnswer);
String billingOpenChannelAnswerString = gson.toJson(billingOpenChannelAnswer);
socketWrapper.sendLine(billingOpenChannelAnswerString);
@ -98,6 +152,9 @@ public class BillingServer {
// OK
state = State.ROAMING;
// start funding
sendUpdateUIBroadcastWithMessage("Start Channel funding");
}
if (state == State.ROAMING) {
@ -117,10 +174,23 @@ public class BillingServer {
Log.d(TAG, "start: Good morning!");
// create new bill
// ToDo: integrate real network data
// ToDo: calculate time correctly
b = Accountant.getInstance().createBill(0,0,1);
NetworkStats.Bucket bucket;
long total_bytes;
try {
bucket = networkStatsManager.querySummaryForDevice(ConnectivityManager.TYPE_WIFI,
"",
Accountant.getInstance().getLastTime() * 1000,
System.currentTimeMillis());
long bytes_received = bucket.getRxBytes();
long bytes_transmitted = bucket.getTxBytes();
total_bytes = bytes_received + bytes_transmitted;
} catch (RemoteException e) {
Log.d(TAG, "start: Can't get the network traffic.");
total_bytes = 0;
}
b = Accountant.getInstance().createBill((int)total_bytes);
// ToDo: integrate real flash channel
latestBill = new BillMessage(b, "", false);
latestBill = new BillMessage(b, "<flash obj>", Accountant.getInstance().isCloseAfterwards());
latestBillString = gson.toJson(latestBill);
socketWrapper.sendLine(latestBillString);
@ -136,11 +206,14 @@ public class BillingServer {
if (latestBill.isCloseAfterwards() || latestBillAnswer.isCloseAfterwards()) {
state = State.CLOSE;
}
sendUpdateUIBroadcastWithMessage("Billing");
}
}
if (state == State.CLOSE) {
Log.d(TAG, "start: state is CLOSE now");
// ToDo: handle the final deposit of the flash channel
// ToDo: sign the transaction
BillingCloseChannel billingCloseChannel = new BillingCloseChannel(0,0,0,0,"", "", "");
@ -150,6 +223,9 @@ public class BillingServer {
String billingCloseChannelAnswerString = socketWrapper.getLineThrowing();
BillingCloseChannelAnswer billingCloseChannelAnswer = gson.fromJson(billingCloseChannelAnswerString, BillingCloseChannelAnswer.class);
// ToDo: validate the signature
// change the ui
sendUpdateUIBroadcastWithMessage("Channel closed");
state = State.CLOSED;
}
@ -158,18 +234,35 @@ public class BillingServer {
boolean attached = false;
while (!attached) {
Log.d(TAG, "start: Attach to tangle please");
Thread.sleep(5000);
}
state = State.FULLY_ATTACHED;
}
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
try {
if (socketWrapper != null) {
socketWrapper.close();
}
} catch (Exception e) {
}
try {
if (serverSocket != null) {
serverSocket.close();
}
} catch (Exception e) {
}
}
}
}
private void createDeadlineGuard() {
// this method measures the time and stops the connection if
// nothing happened after <timeoutMinutes>

View File

@ -1,9 +1,16 @@
package com.flashwifi.wifip2p.broadcast;
import android.app.Activity;
import android.app.Notification;
import android.app.PendingIntent;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.DhcpInfo;
import android.net.NetworkInfo;
import android.net.wifi.WifiManager;
import android.net.wifi.p2p.WifiP2pConfig;
@ -13,26 +20,52 @@ import android.net.wifi.p2p.WifiP2pInfo;
import android.net.wifi.p2p.WifiP2pManager;
import android.os.AsyncTask;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.preference.PreferenceManager;
import android.support.v4.app.NotificationCompat;
import android.text.format.Formatter;
import android.util.Log;
import com.flashwifi.wifip2p.AddressBalanceTransfer;
import com.flashwifi.wifip2p.Constants;
import com.flashwifi.wifip2p.MainActivity;
import com.flashwifi.wifip2p.R;
import com.flashwifi.wifip2p.accesspoint.AccessPointTask;
import com.flashwifi.wifip2p.accesspoint.ConnectTask;
import com.flashwifi.wifip2p.accesspoint.StopAccessPointTask;
import com.flashwifi.wifip2p.billing.Accountant;
import com.flashwifi.wifip2p.billing.BillingClient;
import com.flashwifi.wifip2p.billing.BillingServer;
import com.flashwifi.wifip2p.datastore.PeerStore;
import com.flashwifi.wifip2p.iotaAPI.Requests.WalletTransferRequest;
import com.flashwifi.wifip2p.negotiation.Negotiator;
import com.flashwifi.wifip2p.protocol.BillingOpenChannel;
import com.flashwifi.wifip2p.protocol.BillingOpenChannelAnswer;
import com.flashwifi.wifip2p.protocol.NegotiationFinalization;
import com.flashwifi.wifip2p.protocol.NegotiationOffer;
import com.flashwifi.wifip2p.protocol.NegotiationOfferAnswer;
import org.apache.commons.lang3.ArrayUtils;
import java.io.IOException;
import java.lang.reflect.Method;
import java.math.BigInteger;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import jota.IotaAPI;
import jota.dto.response.GetBalancesResponse;
import jota.dto.response.SendTransferResponse;
import jota.error.ArgumentException;
import jota.model.Transfer;
public class WiFiDirectBroadcastService extends Service {
public final static String TAG = "WiFiService";
@ -75,6 +108,62 @@ public class WiFiDirectBroadcastService extends Service {
AccessPointTask apTask;
boolean apRuns = false;
ConnectTask connectTask;
private boolean negotiatorRunning = false;
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (intent.getAction().equals(Constants.ACTION.STARTFOREGROUND_ACTION)) {
Log.i(TAG, "Received Start Foreground Intent ");
Intent notificationIntent = new Intent(this, MainActivity.class);
notificationIntent.setAction(Constants.ACTION.MAIN_ACTION);
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_CLEAR_TASK);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,
notificationIntent, 0);
/*
Intent previousIntent = new Intent(this, WiFiDirectBroadcastService.class);
previousIntent.setAction(Constants.ACTION.PREV_ACTION);
PendingIntent ppreviousIntent = PendingIntent.getService(this, 0,
previousIntent, 0);
Intent playIntent = new Intent(this, WiFiDirectBroadcastService.class);
playIntent.setAction(Constants.ACTION.PLAY_ACTION);
PendingIntent pplayIntent = PendingIntent.getService(this, 0,
playIntent, 0);*/
Intent stopIntent = new Intent(this, WiFiDirectBroadcastService.class);
stopIntent.setAction(Constants.ACTION.STOPFOREGROUND_ACTION);
PendingIntent pstopIntent = PendingIntent.getService(this, 0,
stopIntent, 0);
Bitmap icon = BitmapFactory.decodeResource(getResources(),
R.drawable.icon_tethering_on);
Notification notification = new NotificationCompat.Builder(this)
.setContentTitle(getString(R.string.app_name))
.setTicker(getString(R.string.app_name))
.setContentText(getString(R.string.notification_doing_nothing))
.setSmallIcon(R.drawable.icon_tethering_on)
.setLargeIcon(
Bitmap.createScaledBitmap(icon, 128, 128, false))
.setContentIntent(pendingIntent)
.setOngoing(true)
.addAction(R.drawable.icon_tethering_off, "Stop",
pstopIntent).build();
startForeground(Constants.NOTIFICATION_ID.FOREGROUND_SERVICE,
notification);
} else if (intent.getAction().equals(
Constants.ACTION.STOPFOREGROUND_ACTION)) {
Log.i(TAG, "Received Stop Foreground Intent");
stopForeground(true);
stopSelf();
}
return START_STICKY;
}
public boolean isSetup() {
return setup;
}
public void enableWiFi() {
WifiManager wifiManager = (WifiManager) getApplicationContext().getSystemService(WIFI_SERVICE);
@ -94,15 +183,21 @@ public class WiFiDirectBroadcastService extends Service {
}
}
public void startBillingServer(){
public void resetBillingState() {
billingClientIsRunning = false;
billingServerIsRunning = false;
}
public void startBillingServer(String mac){
if (!billingServerIsRunning) {
billingServerIsRunning = true;
Runnable task = new Runnable() {
@Override
public void run() {
Log.d(TAG, "run: instantiate billing server");
// ToDo: remove magic numbers
BillingServer billingServer = new BillingServer(100, 20, getApplicationContext());
BillingServer billingServer = new BillingServer(mac, getApplicationContext());
try {
billingServer.start();
@ -115,13 +210,17 @@ public class WiFiDirectBroadcastService extends Service {
};
Log.d(TAG, "startBillingServer");
Thread thread = new Thread(task);
//asyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, params);
//AsyncTask.execute(thread);
threads.add(thread);
AsyncTask.execute(thread);
thread.start();
} else {
Log.d(TAG, "startBillingServer: blocked");
}
}
public void startBillingClient() {
public void startBillingClient(String mac) {
if (!billingClientIsRunning) {
billingClientIsRunning = true;
@ -130,18 +229,34 @@ public class WiFiDirectBroadcastService extends Service {
Runnable task = new Runnable() {
@Override
public void run() {
// ToDo: remove magic numbers
BillingClient billingClient = new BillingClient(getApplicationContext());
// ToDo: get the AP gateway ip address
BillingClient billingClient = new BillingClient(mac, getApplicationContext());
// Gget the AP gateway ip address
// https://stackoverflow.com/questions/9035784/how-to-know-ip-address-of-the-router-from-code-in-android
billingClient.start("192.168.43.1");
final WifiManager manager = (WifiManager) getApplicationContext().getSystemService(WIFI_SERVICE);
final DhcpInfo dhcp = manager.getDhcpInfo();
byte[] myIPAddress = BigInteger.valueOf(dhcp.gateway).toByteArray();
ArrayUtils.reverse(myIPAddress);
InetAddress myInetIP = null;
String routerIP = null;
try {
myInetIP = InetAddress.getByAddress(myIPAddress);
routerIP = myInetIP.getHostAddress();
} catch (UnknownHostException e) {
e.printStackTrace();
routerIP = "192.168.43.1";
}
Log.d(TAG, "DHCP gateway: " + routerIP);
billingClient.start(routerIP);
// ToDo: handle billingServer EXIT CODES
// -> close the roaming etc.
}
};
Thread thread = new Thread(task);
threads.add(thread);
AsyncTask.execute(thread);
thread.start();
//AsyncTask.execute(thread);
} else {
Log.d(TAG, "startBillingClient: blocked");
}
}
@ -214,27 +329,45 @@ public class WiFiDirectBroadcastService extends Service {
}
}
public void startNegotiationServer(final boolean isClient, String macAddress) {
Runnable task = new Runnable() {
@Override
public void run() {
Negotiator negotiator = new Negotiator(isClient, getWFDMacAddress());
Negotiator negotiator = new Negotiator(isClient,
getWFDMacAddress(),
PreferenceManager.getDefaultSharedPreferences(getApplicationContext()),
getBaseContext()
);
String peer_mac_address = null;
while (!isRoaming && enabled && peer_mac_address == null) {
boolean restartAfterwards = true;
int error_count = 0;
int max_error_count = 10;
Negotiator.NegotiationReturn ret = null;
while (!isRoaming && enabled && peer_mac_address == null && restartAfterwards && (error_count < max_error_count)) {
Log.d(TAG, String.format("%d/%d errors", error_count, max_error_count));
Log.d(TAG, "run: " + enabled);
peer_mac_address = negotiator.workAsServer();
// ToDo: use other broadcast for this
// sendUpdateUIBroadcast();
ret = negotiator.workAsServer();
peer_mac_address = ret.mac;
restartAfterwards = ret.restartAfterwards;
if (ret.code != 0) {
sendUpdateUIBroadcastWithMessage(getString(ret.code));
if (restartAfterwards) {
error_count++;
}
}
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
error_count++;
}
if (peer_mac_address == null) {
deletePersistentGroups();
}
}
if (peer_mac_address != null) {
if (peer_mac_address != null && ret != null && ret.code == 0) {
// block the discovery mode due to switch to roaming state
setRoaming(true);
// tell the UI
@ -242,15 +375,22 @@ public class WiFiDirectBroadcastService extends Service {
String ssid = negFin.getHotspotName();
String key = negFin.getHotspotPassword();
sendStartRoamingBroadcast(peer_mac_address, ssid, key);
} else if (peer_mac_address != null) {
PeerStore.getInstance().unselectAll();
}
negotiatorRunning = false;
}
};
if (!isRoaming()) {
if (!isRoaming() && !negotiatorRunning) {
negotiatorRunning = true;
Thread thread = new Thread(task);
threads.add(thread);
AsyncTask.execute(thread);
//AsyncTask.execute(thread);
stopAllTasks();
thread.start();
//stopDiscovery(null);
} else {
Log.d(TAG, "startNegServer: BLOCKED due to roaming state");
}
@ -269,12 +409,24 @@ public class WiFiDirectBroadcastService extends Service {
Runnable task = new Runnable() {
@Override
public void run() {
Negotiator negotiator = new Negotiator(isClient, getWFDMacAddress());
Negotiator negotiator = new Negotiator(
isClient,
getWFDMacAddress(),
PreferenceManager.getDefaultSharedPreferences(getApplicationContext()),
getBaseContext()
);
String peer_mac_address = null;
while (!isRoaming && enabled && peer_mac_address == null) {
boolean restartAfterwards = true;
Negotiator.NegotiationReturn negotiationReturn = null;
while (!isRoaming && enabled && peer_mac_address == null && restartAfterwards && negotiatorRunning) {
Log.d(TAG, "run: " + enabled);
System.out.println(" *******+ work as client *******");
peer_mac_address = negotiator.workAsClient(address.getHostAddress());
negotiationReturn = negotiator.workAsClient(address.getHostAddress());
peer_mac_address = negotiationReturn.mac;
restartAfterwards = negotiationReturn.restartAfterwards;
if (negotiationReturn.code != 0) {
sendUpdateUIBroadcastWithMessage(getString(negotiationReturn.code));
}
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
@ -284,7 +436,7 @@ public class WiFiDirectBroadcastService extends Service {
deletePersistentGroups();
}
}
if (peer_mac_address != null) {
if (peer_mac_address != null && negotiationReturn != null && negotiationReturn.code == 0) {
// block the discovery mode due to switch to roaming state
setRoaming(true);
// tell the UI
@ -292,15 +444,21 @@ public class WiFiDirectBroadcastService extends Service {
String ssid = negFin.getHotspotName();
String key = negFin.getHotspotPassword();
sendStartRoamingBroadcast(peer_mac_address, ssid, key);
} else {
Log.d(TAG, "run: could not start roaming");
}
PeerStore.getInstance().unselectAll();
negotiatorRunning = false;
}
};
if (!isRoaming()) {
if (!isRoaming() && !negotiatorRunning) {
negotiatorRunning = true;
Thread thread = new Thread(task);
threads.add(thread);
AsyncTask.execute(thread);
stopAllTasks();
thread.start();
} else {
Log.d(TAG, "startNegotiationClient: BLOCKED due to roaming state");
Log.d(TAG, "startNegotiationClient: BLOCKED due to roaming state or negotiator running");
}
@ -385,8 +543,10 @@ public class WiFiDirectBroadcastService extends Service {
}
public void startDiscoveryMode(WifiP2pManager.ActionListener action_listener) {
mManager.discoverPeers(mChannel, action_listener);
discoveryModeActive = true;
if (setup) {
mManager.discoverPeers(mChannel, action_listener);
discoveryModeActive = true;
}
}
public boolean isInRoleHotspot() {
@ -410,12 +570,181 @@ public class WiFiDirectBroadcastService extends Service {
}
public void setRoaming(boolean roaming) {
if (roaming) {
if (!roaming) {
stopAllTasks();
}
isRoaming = roaming;
}
public void freezeWiFiP2P() {
}
public void fundChannel(String address) {
// get the necessary data
NegotiationOffer offer = PeerStore.getInstance().getLatestNegotiationOffer(address);
NegotiationOfferAnswer offerAnser = PeerStore.getInstance().getLatestNegotiationOfferAnswer(address);
NegotiationFinalization finalization = PeerStore.getInstance().getLatestFinalization(address);
BillingOpenChannel openChannel = PeerStore.getInstance().getPeer(address).getBillingOpenChannel();
BillingOpenChannelAnswer openChannelAnswer = PeerStore.getInstance().getPeer(address).getBillingOpenChannelAnswer();
String multisigAddress = finalization.getDepositAddressFlashChannel();
int timeoutClientSeconds = openChannel.getTimeoutMinutesClient();
int timeoutHotspotSeconds = openChannelAnswer.getTimeoutMinutesHotspot() * 60;
int timeout = (isInRoleHotspot()) ? timeoutHotspotSeconds : timeoutClientSeconds;
int clientDeposit = finalization.getDepositClientFlashChannelInIota();
int hotspotDeposit = finalization.getDepositServerFlashChannelInIota();
int deposit = (isInRoleHotspot()) ? hotspotDeposit : clientDeposit;
int depositTogether = clientDeposit + hotspotDeposit;
String seed = Accountant.getInstance().getSeed();
Log.d(TAG, "fundChannel: Let's fund " + multisigAddress);
Runnable task = () -> {
Log.d(TAG, "run: fund multisig address");
boolean fundDone = false;
boolean fundIsThere = false;
int fundErrorCount = 0;
int maxFundErrors = 10;
SharedPreferences prefManager = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
boolean testnet = prefManager.getBoolean("pref_key_switch_testnet",false);
IotaAPI api;
if(testnet){
//Testnet node:
api = new IotaAPI.Builder()
.protocol("https")
.host("testnet140.tangle.works")
.port("443")
.build();
}
else{
//Mainnet node:
api = new IotaAPI.Builder()
.protocol("http")
.host("node.iotawallet.info")
.port("14265")
.build();
}
long start = System.currentTimeMillis() / 1000L;
while (((System.currentTimeMillis()/1000L) - start < timeout || !fundDone || !fundIsThere) && fundErrorCount < maxFundErrors) {
SendTransferResponse sendTransferResponse = null;
if (!fundDone) {
Log.d(TAG, "fundChannel: DEPOSIT::" + Integer.toString(deposit));
try {
List<Transfer> transfers = new ArrayList<>();
transfers.add(new Transfer(multisigAddress, deposit, "", ""));
if(testnet) {
Log.d(TAG, "fundChannel: fund on testnet");
sendTransferResponse = api.sendTransfer(seed, 2, 4, 9, transfers, null, null, false);
}
else{
Log.d(TAG, "fundChannel: fund on mainnet");
sendTransferResponse = api.sendTransfer(seed, 2, 4, 18, transfers, null, null, false);
}
} catch (ArgumentException | IllegalAccessError | IllegalStateException e) {
String transferResult = "";
if (e instanceof ArgumentException) {
if (e.getMessage().contains("Sending to a used address.") || e.getMessage().contains("Private key reuse detect!") || e.getMessage().contains("Send to inputs!")) {
transferResult = "Sending to a used address/Private key reuse detect. Error Occurred.";
}
else if(e.getMessage().contains("Failed to connect to node")){
transferResult = "Failed to connect to node";
}
else{
transferResult = "Network Error: Attaching new address failed or Transaction failed";
}
}
if (e instanceof IllegalAccessError) {
transferResult = "Local POW needs to be enabled";
}
fundErrorCount++;
Log.d(TAG, "fundChannel: " + transferResult);
}
if(sendTransferResponse != null){
Boolean[] transferSuccess = sendTransferResponse.getSuccessfully();
Boolean success = true;
for (Boolean status : transferSuccess) {
if(status.equals(false)){
success = false;
fundErrorCount++;
break;
}
}
if(success){
Log.d(TAG, "fundChannel: successfully transferred my part");
fundDone = true;
}
}
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
} else if (fundDone && !fundIsThere) {
// now check the balance until we get it
// check the funding
Log.d(TAG, "fundChannel: checking the balance of the root...");
List<String> addresses = new ArrayList<String>();
addresses.add(multisigAddress);
GetBalancesResponse response = null;
try {
response = api.getBalances(100, addresses);
} catch (ArgumentException e) {
e.printStackTrace();
}
if (response != null) {
if (response.getBalances().length > 0) {
long balance = Integer.parseInt(response.getBalances()[0]);
Log.d(TAG, "fundChannel: Found balance " + response.getBalances()[0]);
if (balance > depositTogether) {
Log.d(TAG, "fundChannel: balance is enough on both sides");
fundIsThere = true;
}
}
}
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
if (fundErrorCount < maxFundErrors) {
Log.d(TAG, "fundChannel: channel funded");
sendUpdateRoamingBroadcastWithMessage("Channel funded");
} else {
Log.d(TAG, "fundChannel: too many fund errors");
}
};
Log.d(TAG, "startFunding");
Thread thread = new Thread(task);
threads.add(thread);
thread.start();
}
/**
* Class used for the client Binder. Because we know this service always
@ -454,7 +783,9 @@ public class WiFiDirectBroadcastService extends Service {
}
public void getPeerList(WifiP2pManager.ActionListener action_listener) {
mManager.discoverPeers(mChannel, action_listener);
if (setup) {
mManager.discoverPeers(mChannel, action_listener);
}
}
public void stopDiscovery(WifiP2pManager.ActionListener action_listener) {
@ -507,6 +838,13 @@ public class WiFiDirectBroadcastService extends Service {
this.sendBroadcast(local);
}
private void sendUpdateRoamingBroadcastWithMessage(String message){
Intent local = new Intent();
local.putExtra("message", message);
local.setAction("com.flashwifi.wifip2p.update_roaming");
this.sendBroadcast(local);
}
public void connect(String address, WifiP2pManager.ActionListener actionListener) {
WifiP2pDevice device;
WifiP2pConfig config = new WifiP2pConfig();

View File

@ -4,6 +4,10 @@ import android.net.wifi.p2p.WifiP2pDevice;
import android.net.wifi.p2p.WifiP2pInfo;
import android.support.annotation.NonNull;
import com.flashwifi.wifip2p.protocol.BillingCloseChannel;
import com.flashwifi.wifip2p.protocol.BillingCloseChannelAnswer;
import com.flashwifi.wifip2p.protocol.BillingOpenChannel;
import com.flashwifi.wifip2p.protocol.BillingOpenChannelAnswer;
import com.flashwifi.wifip2p.protocol.NegotiationFinalization;
import com.flashwifi.wifip2p.protocol.NegotiationOffer;
import com.flashwifi.wifip2p.protocol.NegotiationOfferAnswer;
@ -17,6 +21,7 @@ public class PeerInformation {
private WifiP2pDevice wifiP2pDevice;
private Date lastUpdate;
private boolean selected;
private String errorMessage = "info";
// age stores how long it has been since the last signal from this peer
// it is not stored in seconds but in update cycles
@ -26,6 +31,11 @@ public class PeerInformation {
private NegotiationOfferAnswer latestOfferAnswer;
private NegotiationFinalization latestFinalization;
private BillingOpenChannel billingOpenChannel;
private BillingOpenChannelAnswer billingOpenChannelAnswer;
private BillingCloseChannel billingCloseChannel;
private BillingCloseChannelAnswer billingCloseChannelAnswer;
public PeerInformation() {
selected = false;
age = 0;
@ -55,6 +65,8 @@ public class PeerInformation {
return latestNegotiationOffer;
}
public void setLatestOfferAnswer(NegotiationOfferAnswer latestOfferAnswer) {
this.latestOfferAnswer = latestOfferAnswer;
}
@ -86,4 +98,44 @@ public class PeerInformation {
public void setSelected(boolean selected) {
this.selected = selected;
}
public void setErrorMessage(String errorMessage) {
this.errorMessage = errorMessage;
}
public String getErrorMessage() {
return errorMessage;
}
public BillingOpenChannel getBillingOpenChannel() {
return billingOpenChannel;
}
public void setBillingOpenChannel(BillingOpenChannel billingOpenChannel) {
this.billingOpenChannel = billingOpenChannel;
}
public BillingOpenChannelAnswer getBillingOpenChannelAnswer() {
return billingOpenChannelAnswer;
}
public void setBillingOpenChannelAnswer(BillingOpenChannelAnswer billingOpenChannelAnswer) {
this.billingOpenChannelAnswer = billingOpenChannelAnswer;
}
public BillingCloseChannel getBillingCloseChannel() {
return billingCloseChannel;
}
public void setBillingCloseChannel(BillingCloseChannel billingCloseChannel) {
this.billingCloseChannel = billingCloseChannel;
}
public BillingCloseChannelAnswer getBillingCloseChannelAnswer() {
return billingCloseChannelAnswer;
}
public void setBillingCloseChannelAnswer(BillingCloseChannelAnswer billingCloseChannelAnswer) {
this.billingCloseChannelAnswer = billingCloseChannelAnswer;
}
}

View File

@ -6,6 +6,7 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ProgressBar;
import android.widget.TableRow;
import android.widget.TextView;
@ -41,8 +42,7 @@ public class PeerListAdapter extends ArrayAdapter<PeerInformation> {
TextView tt1 = (TextView) v.findViewById(R.id.deviceName);
TextView tt2 = (TextView) v.findViewById(R.id.categoryId);
TextView tt3 = (TextView) v.findViewById(R.id.description);
TextView tt4 = (TextView) v.findViewById(R.id.ipAddr);
TextView tt5 = (TextView) v.findViewById(R.id.iotaPrice);
TextView tt4 = (TextView) v.findViewById(R.id.iotaPrice);
WifiP2pDevice device = p.getWifiP2pDevice();
@ -58,22 +58,22 @@ public class PeerListAdapter extends ArrayAdapter<PeerInformation> {
NegotiationOffer offer = p.getLatestNegotiationOffer();
if (offer != null) {
tt5.setText(Integer.toString(offer.getIotaPerMegabyte()));
tt4.setText(Integer.toString(offer.getIotaPerMegabyte()) + "i");
}
if (p.getIpAddress() != null) {
tt4.setText(p.getIpAddress());
if (!p.isSelected()) {
ProgressBar progress_bar = (ProgressBar) v.findViewById(R.id.progressConnection);
progress_bar.setVisibility(View.GONE);
}
if (tt3 != null)
tt3.setText(String.format("%s", Integer.toString(p.getAge())));
if (tt3 != null) {
tt3.setText(p.getErrorMessage());
}
}
return v;
}
}

View File

@ -1,5 +1,9 @@
package com.flashwifi.wifip2p.datastore;
import com.flashwifi.wifip2p.protocol.BillingCloseChannel;
import com.flashwifi.wifip2p.protocol.BillingCloseChannelAnswer;
import com.flashwifi.wifip2p.protocol.BillingOpenChannel;
import com.flashwifi.wifip2p.protocol.BillingOpenChannelAnswer;
import com.flashwifi.wifip2p.protocol.NegotiationFinalization;
import com.flashwifi.wifip2p.protocol.NegotiationOffer;
import com.flashwifi.wifip2p.protocol.NegotiationOfferAnswer;
@ -87,6 +91,20 @@ public class PeerStore {
getOrCreatePeer(macAddress.toLowerCase()).setLatestOffer(offer);
}
public void setErrorMessage(String macAddress, String msg) {
getOrCreatePeer(macAddress.toLowerCase()).setErrorMessage(msg);
}
public void setSelected(String macAddress, boolean selected) {
getOrCreatePeer(macAddress.toLowerCase()).setSelected(selected);
}
public void unselectAll() {
for (PeerInformation p: peers.values()) {
p.setSelected(false);
}
}
public void setLatestOfferAnswer(String macAddress, NegotiationOfferAnswer answer) {
getOrCreatePeer(macAddress.toLowerCase()).setLatestOfferAnswer(answer);
}
@ -102,7 +120,46 @@ public class PeerStore {
return null;
}
public NegotiationOffer getLatestNegotiationOffer(String macAddress) {
if (peers.containsKey(macAddress.toLowerCase())) {
return peers.get(macAddress.toLowerCase()).getLatestNegotiationOffer();
}
return null;
}
public NegotiationOfferAnswer getLatestNegotiationOfferAnswer(String macAddress) {
if (peers.containsKey(macAddress.toLowerCase())) {
return peers.get(macAddress.toLowerCase()).getLatestOfferAnswer();
}
return null;
}
public void setIPAddress(String macAddress, InetAddress IPAddress) {
getOrCreatePeer(macAddress.toLowerCase()).setIPAddress(IPAddress.getHostAddress());
}
public void setLatestBillingOpenChannel(String macAddress, BillingOpenChannel o) {
getOrCreatePeer(macAddress.toLowerCase()).setBillingOpenChannel(o);
}
public void setLatestBillingOpenChannelAnswer(String macAddress, BillingOpenChannelAnswer o) {
getOrCreatePeer(macAddress.toLowerCase()).setBillingOpenChannelAnswer(o);
}
public void setLatestBillingCloseChannel(String macAddress, BillingCloseChannel o) {
getOrCreatePeer(macAddress.toLowerCase()).setBillingCloseChannel(o);
}
public void setLatestBillingCloseChannelAnswer(String macAddress, BillingCloseChannelAnswer o) {
getOrCreatePeer(macAddress.toLowerCase()).setBillingCloseChannelAnswer(o);
}
public PeerInformation getPeer(String address) {
address = address.toLowerCase();
if (peers.containsKey(address)) {
return peers.get(address);
}
return null;
}
}

View File

@ -0,0 +1,48 @@
package com.flashwifi.wifip2p.iotaAPI.Requests.Model;
import com.google.api.client.json.GenericJson;
import com.google.api.client.util.Key;
public class TokenGenJSONResponse extends GenericJson {
@Key("seed")
private String seed;
@Key("address")
private String address;
@Key("amount")
private Integer amount;
private String success;
public Integer getAmount() {
return amount;
}
public void setAmount(Integer amount) {
this.amount = amount;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getSeed() {
return seed;
}
public void setSeed(String seed) {
this.seed = seed;
}
public String getSuccess() {
return success;
}
public void setSuccess(String success) {
this.success = success;
}
}

View File

@ -1,199 +0,0 @@
package com.flashwifi.wifip2p.iotaAPI.Requests;
/**
* Created by Toby on 1/6/2018.
*/
import android.content.Context;
import android.content.SharedPreferences;
import android.os.AsyncTask;
import android.os.Handler;
import android.os.Message;
import com.flashwifi.wifip2p.AddressBalanceTransfer;
import java.util.ArrayList;
import java.util.List;
import jota.IotaAPI;
import jota.dto.response.GetBalancesResponse;
import jota.dto.response.GetNewAddressResponse;
import jota.error.ArgumentException;
import jota.model.Transaction;
public class WalletAddressAndBalanceChecker extends AsyncTask<Void, Void, Void> {
private static final int BALANCE_RETRIEVE_TASK_COMPLETE = 1;
private static final int FUND_WALLET = 0;
private static final int WITHDRAW_WALLET = 1;
private static IotaAPI api;
private static Context context;
private String prefFile;
private String seed;
private Handler mHandler;
private int type;
private Boolean updateMessage;
//GetNodeInfoResponse response = api.getNodeInfo();
public WalletAddressAndBalanceChecker(Context inActivity, String inPrefFile, String inSeed, Handler inMHandler, int inType, Boolean inUpdateMessage) {
context = inActivity;
prefFile = inPrefFile;
seed = inSeed;
mHandler = inMHandler;
type = inType;
updateMessage = inUpdateMessage;
//Mainnet node:
/*
api = new IotaAPI.Builder()
.protocol("http")
.host("node.iotawallet.info")
.port("14265")
.build();
*/
//Testnet node:
api = new IotaAPI.Builder()
.protocol("https")
.host("testnet140.tangle.works")
.port("443")
.build();
}
@Override
protected Void doInBackground(Void... voids) {
if(context != null){
List<String> addressList = getAddress(seed);
if(addressList != null && addressList.get(0) == "Unable to resolve host"){
AddressBalanceTransfer addressBalanceTransfer = new AddressBalanceTransfer(null,null,"hostError");
Message completeMessage = mHandler.obtainMessage(BALANCE_RETRIEVE_TASK_COMPLETE, addressBalanceTransfer);
completeMessage.sendToTarget();
}
else if(addressList != null){
String depositAddress = addressList.get(addressList.size()-1);
String balance = getBalance(addressList);
if(balance != null){
if(type == WITHDRAW_WALLET && updateMessage == false){
AddressBalanceTransfer addressBalanceTransfer = new AddressBalanceTransfer(depositAddress,balance,"noErrorNoUpdateMessage");
Message completeMessage = mHandler.obtainMessage(BALANCE_RETRIEVE_TASK_COMPLETE,addressBalanceTransfer);
completeMessage.sendToTarget();
}
else{
AddressBalanceTransfer addressBalanceTransfer = new AddressBalanceTransfer(depositAddress,balance,"noError");
Message completeMessage = mHandler.obtainMessage(BALANCE_RETRIEVE_TASK_COMPLETE,addressBalanceTransfer);
completeMessage.sendToTarget();
}
}
else{
//Balance Retrieval Error
AddressBalanceTransfer addressBalanceTransfer = new AddressBalanceTransfer(null,null,"balanceError");
Message completeMessage = mHandler.obtainMessage(BALANCE_RETRIEVE_TASK_COMPLETE, addressBalanceTransfer);
completeMessage.sendToTarget();
}
}
else{
//Address Retrieval Error
AddressBalanceTransfer addressBalanceTransfer = new AddressBalanceTransfer(null,null,"addressError");
Message completeMessage = mHandler.obtainMessage(BALANCE_RETRIEVE_TASK_COMPLETE, addressBalanceTransfer);
completeMessage.sendToTarget();
}
}
return null;
}
public String getBalance(List<String> inAddresses){
String[] balanceArray;
try {
GetBalancesResponse balanceResultResponse = api.getBalances(100, inAddresses);
balanceArray = balanceResultResponse.getBalances();
} catch (ArgumentException | IllegalStateException e) {
e.printStackTrace();
return null;
}
if(balanceArray.length>1){
return balanceArray[balanceArray.length-2];
}
else{
return balanceArray[balanceArray.length-1];
}
}
public List<String> getAddress(String seed) {
Boolean foundAddress = false;
List<String> addressList = new ArrayList<>();
int keyIndex = getKeyIndex();
while(foundAddress == false){
GetNewAddressResponse addressResponse = null;
try {
addressResponse = api.getNewAddress(seed, 2, keyIndex, false, 1, false);
} catch (ArgumentException e) {
e.printStackTrace();
}
if(addressResponse != null) {
addressList.add(addressResponse.getAddresses().get(0));
String[] addressesCheckArray = new String[1];
addressesCheckArray[0] = addressResponse.getAddresses().get(0);
List<Transaction> transactionsForAddress = null;
try {
transactionsForAddress = api.findTransactionObjectsByAddresses(addressesCheckArray);
} catch (ArgumentException | IllegalStateException | IllegalAccessError e) {
e.printStackTrace();
if(e.getMessage().contains("Unable to resolve host")){
List<String> errorStringList = new ArrayList<>();
errorStringList.add("Unable to resolve host");
return errorStringList;
}
}
if(transactionsForAddress.isEmpty() || (transactionsForAddress.size() == 0 || transactionsForAddress.equals(null))){
//Transactions not found, use this address
foundAddress = true;
}
else{
//Found transactions, increment for new address
keyIndex = keyIndex + 1;
}
}
}
if(keyIndex == 0){
//Put the initial address to search. No transactions for the seed yet.
putKeyIndex(keyIndex);
}
else{
//Put the second last address to search
putKeyIndex(keyIndex-1);
}
return addressList;
}
private int getKeyIndex() {
SharedPreferences sharedPref = context.getSharedPreferences(prefFile, Context.MODE_PRIVATE);
int keyIndex = sharedPref.getInt("keyIndex",0);
return keyIndex;
}
private void putKeyIndex(int inKeyIndex) {
SharedPreferences sharedPref = context.getSharedPreferences(
prefFile, Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPref.edit();
editor.putInt("keyIndex", inKeyIndex);
editor.apply();
}
}

View File

@ -0,0 +1,176 @@
package com.flashwifi.wifip2p.iotaAPI.Requests;
import android.content.Context;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import com.flashwifi.wifip2p.R;
import java.util.ArrayList;
import java.util.List;
import jota.IotaAPI;
import jota.dto.response.GetInclusionStateResponse;
import jota.dto.response.GetNewAddressResponse;
import jota.error.ArgumentException;
import jota.model.Transaction;
public class WalletAddressChecker {
private static IotaAPI api;
private Context context;
private String prefFile;
boolean containsPendingTransaction = false;
boolean keyIndexChanged = false;
public WalletAddressChecker(Context inContext, String inPrefFile){
context = inContext;
prefFile = inPrefFile;
SharedPreferences prefManager = PreferenceManager.getDefaultSharedPreferences(context);
Boolean testnet = prefManager.getBoolean("pref_key_switch_testnet",false);
Boolean testnetPrivate = prefManager.getBoolean("pref_key_switch_testnet_private",false);
if(testnet){
//Testnet node:
if(testnetPrivate){
//Private test node
api = new IotaAPI.Builder()
.protocol(context.getResources().getString(R.string.protocolPrivateTestnetNode))
.host(context.getResources().getString(R.string.hostPrivateTestnetNode))
.port(context.getResources().getString(R.string.portPrivateTestnetNode))
.build();
}
else{
//Public test node
api = new IotaAPI.Builder()
.protocol(context.getResources().getString(R.string.protocolPublicTestnetNode))
.host(context.getResources().getString(R.string.hostPublicTestnetNode))
.port(context.getResources().getString(R.string.portPublicTestnetNode))
.build();
}
}
else{
//Mainnet node:
api = new IotaAPI.Builder()
.protocol(context.getResources().getString(R.string.protocolDefaultMainnetNode))
.host(context.getResources().getString(R.string.hostDefaultMainnetNode))
.port(context.getResources().getString(R.string.portDefaultMainnetNode))
.build();
}
}
public List<String> getAddress(String seed) {
Boolean foundAddress = false;
List<String> addressList = new ArrayList<>();
int keyIndex = getKeyIndex();
ArrayList<String> hashStringList = new ArrayList<>();
while(foundAddress == false){
GetNewAddressResponse addressResponse = null;
try {
SharedPreferences prefManager = PreferenceManager.getDefaultSharedPreferences(context);
String security = prefManager.getString("pref_key_security","2");
int securityInt = Integer.parseInt(security);
addressResponse = api.getNewAddress(seed, securityInt, keyIndex, true, 1, false);
} catch (ArgumentException e) {
e.printStackTrace();
return addressList;
}
if(addressResponse != null) {
addressList.add(addressResponse.getAddresses().get(0));
String[] addressesCheckArray = new String[1];
addressesCheckArray[0] = addressResponse.getAddresses().get(0);
List<Transaction> transactionsForAddress = null;
try {
transactionsForAddress = api.findTransactionObjectsByAddresses(addressesCheckArray);
} catch (ArgumentException | IllegalStateException | IllegalAccessError e) {
e.printStackTrace();
if(e.getMessage().contains("Unable to resolve host")){
List<String> errorStringList = new ArrayList<>();
errorStringList.add("Unable to resolve host");
return errorStringList;
}
}
if(transactionsForAddress == null || transactionsForAddress.isEmpty() || (transactionsForAddress.size() == 0)){
//Transactions not found, use this address
foundAddress = true;
}
else{
//Found transactions, increment for new address
String curHash = transactionsForAddress.get(0).getHash();
hashStringList.add(curHash);
keyIndex = keyIndex + 1;
}
}
}
String[] hashStringArray = new String[hashStringList.size()];
int hashIndex = 0;
//Convert hash String List to String Array
for (String curHash : hashStringList) {
hashStringArray[hashIndex] = curHash;
hashIndex = hashIndex + 1;
}
//Check whether pending transactions exist
containsPendingTransaction = false;
keyIndexChanged = false;
GetInclusionStateResponse inclusionResponse;
try {
inclusionResponse = api.getLatestInclusion(hashStringArray);
} catch (ArgumentException | IllegalStateException e) {
e.printStackTrace();
return addressList;
}
boolean[] states = inclusionResponse.getStates();
for (boolean state : states) {
if(!state){
containsPendingTransaction = true;
}
}
if(!containsPendingTransaction){
//all confirmed transactions, ok to change keyIndex
if(keyIndex != getKeyIndex()){
keyIndexChanged = true;
putKeyIndex(keyIndex);
}
}
return addressList;
}
private int getKeyIndex() {
SharedPreferences sharedPref = context.getSharedPreferences(prefFile, Context.MODE_PRIVATE);
int keyIndex = sharedPref.getInt("keyIndex",0);
return keyIndex;
}
private void putKeyIndex(int inKeyIndex) {
SharedPreferences sharedPref = context.getSharedPreferences(
prefFile, Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPref.edit();
editor.putInt("keyIndex", inKeyIndex);
editor.apply();
}
public boolean getContainsPendingTransaction() {
return containsPendingTransaction;
}
public boolean getkeyIndexChanged() {
return keyIndexChanged;
}
}

View File

@ -0,0 +1,217 @@
package com.flashwifi.wifip2p.iotaAPI.Requests;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.AsyncTask;
import android.os.Handler;
import android.os.Message;
import android.preference.PreferenceManager;
import com.flashwifi.wifip2p.AddressBalanceTransfer;
import com.flashwifi.wifip2p.R;
import java.text.DateFormat;
import java.util.Date;
import java.util.List;
import jota.IotaAPI;
import jota.dto.response.GetBalancesAndFormatResponse;
import jota.dto.response.GetBalancesResponse;
import jota.error.ArgumentException;
import jota.utils.StopWatch;
public class WalletBalanceChecker extends AsyncTask<Void, Void, Void> {
private static final int BALANCE_RETRIEVE_TASK_COMPLETE = 1;
private static final int FUND_WALLET = 0;
private static final int WITHDRAW_WALLET = 1;
private static final int PREF_UPDATE = 2;
private static IotaAPI api;
private static Context context;
private String prefFile;
private String seed;
private Handler mHandler;
private int type;
private Boolean updateMessage;
public WalletBalanceChecker(Context inActivity, String inPrefFile, String inSeed, Handler inMHandler, int inType, Boolean inUpdateMessage) {
context = inActivity;
prefFile = inPrefFile;
seed = inSeed;
mHandler = inMHandler;
type = inType;
updateMessage = inUpdateMessage;
SharedPreferences prefManager = PreferenceManager.getDefaultSharedPreferences(context);
Boolean testnet = prefManager.getBoolean("pref_key_switch_testnet",false);
Boolean testnetPrivate = prefManager.getBoolean("pref_key_switch_testnet_private",false);
if(testnet){
//Testnet node:
if(testnetPrivate){
//Private test node
api = new IotaAPI.Builder()
.protocol(context.getResources().getString(R.string.protocolPrivateTestnetNode))
.host(context.getResources().getString(R.string.hostPrivateTestnetNode))
.port(context.getResources().getString(R.string.portPrivateTestnetNode))
.build();
}
else{
//Public test node
api = new IotaAPI.Builder()
.protocol(context.getResources().getString(R.string.protocolPublicTestnetNode))
.host(context.getResources().getString(R.string.hostPublicTestnetNode))
.port(context.getResources().getString(R.string.portPublicTestnetNode))
.build();
}
}
else{
//Mainnet node:
api = new IotaAPI.Builder()
.protocol(context.getResources().getString(R.string.protocolDefaultMainnetNode))
.host(context.getResources().getString(R.string.hostDefaultMainnetNode))
.port(context.getResources().getString(R.string.portDefaultMainnetNode))
.build();
}
}
@Override
protected Void doInBackground(Void... voids) {
if(context != null){
WalletAddressChecker addressChecker = new WalletAddressChecker(context,prefFile);
List<String> addressList = addressChecker.getAddress(seed);
boolean containsPendingTransactions = addressChecker.getContainsPendingTransaction();
boolean keyIndexChanged = addressChecker.getkeyIndexChanged();
if(addressList != null && addressList.get(0).equals("Unable to resolve host")){
AddressBalanceTransfer addressBalanceTransfer = new AddressBalanceTransfer(null,null,"hostError");
Message completeMessage = mHandler.obtainMessage(BALANCE_RETRIEVE_TASK_COMPLETE, addressBalanceTransfer);
completeMessage.sendToTarget();
}
else if(addressList != null){
String depositAddress = addressList.get(addressList.size()-1);
String balance = getBalance(addressList, containsPendingTransactions, keyIndexChanged);
if(balance != null){
if(type == WITHDRAW_WALLET && updateMessage == false){
AddressBalanceTransfer addressBalanceTransfer = new AddressBalanceTransfer(depositAddress,balance,"noErrorNoUpdateMessage");
Message completeMessage = mHandler.obtainMessage(BALANCE_RETRIEVE_TASK_COMPLETE,addressBalanceTransfer);
completeMessage.sendToTarget();
}
else{
AddressBalanceTransfer addressBalanceTransfer = new AddressBalanceTransfer(depositAddress,balance,"noError");
Message completeMessage = mHandler.obtainMessage(BALANCE_RETRIEVE_TASK_COMPLETE,addressBalanceTransfer);
completeMessage.sendToTarget();
}
}
else{
//Balance Retrieval Error
AddressBalanceTransfer addressBalanceTransfer = new AddressBalanceTransfer(null,null,"balanceError");
Message completeMessage = mHandler.obtainMessage(BALANCE_RETRIEVE_TASK_COMPLETE, addressBalanceTransfer);
completeMessage.sendToTarget();
}
}
else{
//Address Retrieval Error
AddressBalanceTransfer addressBalanceTransfer = new AddressBalanceTransfer(null,null,"addressError");
Message completeMessage = mHandler.obtainMessage(BALANCE_RETRIEVE_TASK_COMPLETE, addressBalanceTransfer);
completeMessage.sendToTarget();
}
}
return null;
}
public String getBalance(List<String> inAddresses, boolean containsPendingTransactions, boolean keyIndexChanged){
String updatedBalanceString;
try {
StopWatch stopWatch = new StopWatch();
SharedPreferences prefManager = PreferenceManager.getDefaultSharedPreferences(context);
String security = prefManager.getString("pref_key_security","2");
int securityInt = Integer.parseInt(security);
GetBalancesAndFormatResponse balanceResponse = api.getBalanceAndFormat(inAddresses, 0, 0, stopWatch, securityInt);
long total = balanceResponse.getTotalBalance();
long storedBaseBalance = Long.parseLong(getBaseSharedPrefKeyBalance());
long updatedBaseBalance = storedBaseBalance + total;
updatedBalanceString = Long.toString(updatedBaseBalance);
//Pending Transaction, no new confirmed transactions
if(containsPendingTransactions && !keyIndexChanged){
//No action required
}
//Pending Transaction, new confirmed transactions
else if(containsPendingTransactions && keyIndexChanged){
putSharedPrefBalance(updatedBalanceString);
}
//No Pending Transactions, no new confirmed transactions
else if(!containsPendingTransactions && !keyIndexChanged){
//No action required
}
//No Pending Transactions, new confirmed transactions
else if(!containsPendingTransactions && keyIndexChanged){
putBaseSharedPrefBalance(updatedBalanceString);
updatedBalanceString = Long.toString(updatedBaseBalance);
putSharedPrefBalance(updatedBalanceString);
}
} catch (ArgumentException | IllegalStateException e) {
e.printStackTrace();
return getSharedPrefKeyBalance()+"i (cached: "+getSharedPrefKeyBalanceDateUpdate()+")";
}
String currentDateTimeString = DateFormat.getDateTimeInstance().format(new Date());
putSharedPrefBalanceDateUpdate(currentDateTimeString);
return updatedBalanceString+"i";
}
private void putSharedPrefBalanceDateUpdate(String currentDateTimeString) {
SharedPreferences sharedPref = context.getSharedPreferences(
prefFile, Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPref.edit();
editor.putString("balanceDateUpdate", currentDateTimeString);
editor.apply();
}
private String getSharedPrefKeyBalanceDateUpdate() {
SharedPreferences sharedPref = context.getSharedPreferences(prefFile, Context.MODE_PRIVATE);
String defaultValue = "0";
String storedBalance = sharedPref.getString("balanceDateUpdate",defaultValue);
return storedBalance;
}
private String getSharedPrefKeyBalance() {
SharedPreferences sharedPref = context.getSharedPreferences(prefFile, Context.MODE_PRIVATE);
String defaultValue = "0";
String storedBalance = sharedPref.getString("balance",defaultValue);
return storedBalance;
}
private void putSharedPrefBalance(String inBalance) {
SharedPreferences sharedPref = context.getSharedPreferences(
prefFile, Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPref.edit();
editor.putString("balance", inBalance);
editor.apply();
}
private String getBaseSharedPrefKeyBalance() {
SharedPreferences sharedPref = context.getSharedPreferences(prefFile, Context.MODE_PRIVATE);
String defaultValue = "0";
String storedBalance = sharedPref.getString("baseBalance",defaultValue);
return storedBalance;
}
private void putBaseSharedPrefBalance(String inBalance) {
SharedPreferences sharedPref = context.getSharedPreferences(
prefFile, Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPref.edit();
editor.putString("baseBalance", inBalance);
editor.apply();
}
}

View File

@ -0,0 +1,171 @@
package com.flashwifi.wifip2p.iotaAPI.Requests;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.AsyncTask;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.preference.PreferenceManager;
import com.flashwifi.wifip2p.AddressBalanceTransfer;
import com.flashwifi.wifip2p.R;
import com.flashwifi.wifip2p.iotaAPI.Requests.Model.TokenGenJSONResponse;
import com.google.api.client.http.GenericUrl;
import com.google.api.client.http.HttpBackOffUnsuccessfulResponseHandler;
import com.google.api.client.http.HttpRequest;
import com.google.api.client.http.HttpRequestFactory;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.JsonObjectParser;
import com.google.api.client.json.jackson2.JacksonFactory;
import com.google.api.client.util.ExponentialBackOff;
import com.google.gson.reflect.TypeToken;
import java.io.IOException;
import java.lang.reflect.Type;
import java.util.List;
public class WalletTestnetTokenGen extends AsyncTask<Void, Void, Void> {
private static final int TOKEN_TESTNET_RETRIEVE_TASK_COMPLETE = 0;
private static final int TOKEN_TESTNET_STATUS_UPDATE = 1;
private static final int TRANSFER_TASK_COMPLETE = 2;
private static String seed;
private Handler settingsFragmentHandler;
private Handler testnetTokenGenHandler;
private String prefFile;
static HttpTransport HTTP_TRANSPORT = new NetHttpTransport();
static JsonFactory JSON_FACTORY = new JacksonFactory();
private static Context context;
public WalletTestnetTokenGen(Handler inMHandler, Context inContext, String inPrefFile, String inSeed){
settingsFragmentHandler = inMHandler;
context = inContext;
prefFile = inPrefFile;
seed = inSeed;
//Handle post-asynctask activities of updating UI
testnetTokenGenHandler = new Handler(Looper.getMainLooper()) {
@Override
public void handleMessage(Message inputMessage) {
switch (inputMessage.what) {
case TRANSFER_TASK_COMPLETE:
AddressBalanceTransfer addressBalanceTransfer = (AddressBalanceTransfer) inputMessage.obj;
String message = addressBalanceTransfer.getMessage();
//Send completion of send funds to settings fragment
Message completeMessage = settingsFragmentHandler.obtainMessage(TOKEN_TESTNET_RETRIEVE_TASK_COMPLETE,message);
completeMessage.sendToTarget();
}
}
};
}
public TokenGenJSONResponse genToken() {
HttpRequestFactory requestFactory
= HTTP_TRANSPORT.createRequestFactory(
(HttpRequest request) -> {
request.setParser(new JsonObjectParser(JSON_FACTORY));
});
HttpRequest request = null;
try {
SharedPreferences prefManager = PreferenceManager.getDefaultSharedPreferences(context);
Boolean testnetPrivate = prefManager.getBoolean("pref_key_switch_testnet_private",false);
if(testnetPrivate){
request = requestFactory.buildGetRequest(new GenericUrl(context.getResources().getString(R.string.generatorPrivateTestnetNode)));
//Set timeout to 10 min
request.setConnectTimeout(300000);
request.setReadTimeout(600000);
}else{
request = requestFactory.buildGetRequest(new GenericUrl(context.getResources().getString(R.string.generatorPublicTestnetNode)));
//Set timeout to 10 min
request.setConnectTimeout(300000);
request.setReadTimeout(600000);
}
} catch (IOException e) {
e.printStackTrace();
}
//TODO: Set timeout
/*
ExponentialBackOff backoff = new ExponentialBackOff.Builder()
.setInitialIntervalMillis(300000)
.setMaxElapsedTimeMillis(900000)
.setMaxIntervalMillis(600000)
.setMultiplier(1.5)
.setRandomizationFactor(0.999)
.build();
request.setUnsuccessfulResponseHandler(
new HttpBackOffUnsuccessfulResponseHandler(backoff));
*/
Type type = new TypeToken<TokenGenJSONResponse>() {}.getType();
TokenGenJSONResponse token = new TokenGenJSONResponse();
try{
token = (TokenGenJSONResponse) request
.execute()
.parseAs(type);
token.setSuccess("Success");
}
catch (Exception e){
if(e.toString().contains("Connection closed by peer")){
//Could not reach token gen page
token.setSuccess("Connection Error");
e.printStackTrace();
}
else if(e.toString().contains("Unable to resolve host")){
//Could not reach token gen page
token.setSuccess("Unable to resolve host. Please try again.");
e.printStackTrace();
}
else{
//Unknown error
token.setSuccess("Unknown Error. Please try again.");
e.printStackTrace();
}
}
return token;
}
@Override
protected Void doInBackground(Void... voids) {
TokenGenJSONResponse token = genToken();
if(token.getSuccess().equals("Success")){
WalletAddressChecker addressChecker = new WalletAddressChecker(context,prefFile);
List<String> destAddressses = addressChecker.getAddress(seed);
transferToWallet(destAddressses, token);
}
else{
Message completeMessage = settingsFragmentHandler.obtainMessage(TOKEN_TESTNET_RETRIEVE_TASK_COMPLETE,token.getSuccess());
completeMessage.sendToTarget();
}
return null;
}
private void transferToWallet(List<String> destAddressses, TokenGenJSONResponse token) {
if(destAddressses != null && destAddressses.get(0).equals("Unable to resolve host")){
//Host Error
Message completeMessage = settingsFragmentHandler.obtainMessage(TOKEN_TESTNET_RETRIEVE_TASK_COMPLETE, "hostError");
completeMessage.sendToTarget();
}
else if(destAddressses != null){
//No Address Retrieval Error
Message completeMessage = settingsFragmentHandler.obtainMessage(TOKEN_TESTNET_STATUS_UPDATE, "Sending");
completeMessage.sendToTarget();
String destAddress = destAddressses.get(destAddressses.size()-1);
WalletTransferRequest transferRequest = new WalletTransferRequest(destAddress,token.getSeed(),token.getAmount().toString(),"","",context,testnetTokenGenHandler);
transferRequest.execute();
}
else{
//Address Retrieval Error
Message completeMessage = settingsFragmentHandler.obtainMessage(TOKEN_TESTNET_RETRIEVE_TASK_COMPLETE,"addressError");
completeMessage.sendToTarget();
}
}
}

View File

@ -1,11 +1,14 @@
package com.flashwifi.wifip2p.iotaAPI.Requests;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.AsyncTask;
import android.os.Handler;
import android.os.Message;
import android.preference.PreferenceManager;
import com.flashwifi.wifip2p.AddressBalanceTransfer;
import com.flashwifi.wifip2p.R;
import java.util.ArrayList;
import java.util.List;
@ -21,6 +24,8 @@ public class WalletTransferRequest extends AsyncTask<Void, Void, Void> {
private static IotaAPI api;
private static Context context;
Boolean testnet;
Boolean testnetPrivate;
private String appWalletSeed;
private String sendAddress;
private String sendAmount;
@ -39,28 +44,41 @@ public class WalletTransferRequest extends AsyncTask<Void, Void, Void> {
context = inContext;
mHandler = inMHandler;
//Mainnet node:
/*
api = new IotaAPI.Builder()
.protocol("http")
.host("node.iotawallet.info")
.port("14265")
.build();
*/
//Testnet node:
api = new IotaAPI.Builder()
.protocol("https")
.host("testnet140.tangle.works")
.port("443")
.build();
SharedPreferences prefManager = PreferenceManager.getDefaultSharedPreferences(context);
testnet = prefManager.getBoolean("pref_key_switch_testnet",false);
testnetPrivate = prefManager.getBoolean("pref_key_switch_testnet_private",false);
if(testnet){
//Testnet node:
if(testnetPrivate){
//Private test node
api = new IotaAPI.Builder()
.protocol(context.getResources().getString(R.string.protocolPrivateTestnetNode))
.host(context.getResources().getString(R.string.hostPrivateTestnetNode))
.port(context.getResources().getString(R.string.portPrivateTestnetNode))
.build();
}
else{
//Public test node
api = new IotaAPI.Builder()
.protocol(context.getResources().getString(R.string.protocolPublicTestnetNode))
.host(context.getResources().getString(R.string.hostPublicTestnetNode))
.port(context.getResources().getString(R.string.portPublicTestnetNode))
.build();
}
}
else{
//Mainnet node:
api = new IotaAPI.Builder()
.protocol(context.getResources().getString(R.string.protocolDefaultMainnetNode))
.host(context.getResources().getString(R.string.hostDefaultMainnetNode))
.port(context.getResources().getString(R.string.portDefaultMainnetNode))
.build();
}
}
@Override
protected Void doInBackground(Void... voids) {
sendRequest();
String result = null;
if(context != null){
@ -82,26 +100,36 @@ public class WalletTransferRequest extends AsyncTask<Void, Void, Void> {
SendTransferResponse sendTransferResponse = null;
SharedPreferences prefManager = PreferenceManager.getDefaultSharedPreferences(context);
String security = prefManager.getString("pref_key_security","2");
int securityInt = Integer.parseInt(security);
try {
//Mainnet
//sendTransferResponse = api.sendTransfer(appWalletSeed, 2, 4, 18, transfers, null, null, false);
if(testnet) {
//Testnet
sendTransferResponse = api.sendTransfer(appWalletSeed, 2, 4, 9, transfers, null, null, false);
if(testnetPrivate){
sendTransferResponse = api.sendTransfer(appWalletSeed, securityInt, 4, 3, transfers, null, null, false);
}
else{
sendTransferResponse = api.sendTransfer(appWalletSeed, securityInt, 4, 9, transfers, null, null, false);
}
}
else{
//Mainnet
sendTransferResponse = api.sendTransfer(appWalletSeed, securityInt, 4, 14, transfers, null, null, false);
}
} catch (ArgumentException | IllegalAccessError | IllegalStateException e) {
if (e instanceof ArgumentException) {
if (e.getMessage().contains("Sending to a used address.") || e.getMessage().contains("Private key reuse detect!") || e.getMessage().contains("Send to inputs!")) {
transferResult = "Sending to a used address/Private key reuse detect. Error Occurred.";
}
else if(e.getMessage().contains("Failed to connect to")){
transferResult = "Failed to connect to";
else if(e.getMessage().contains("Failed to connect to node")){
transferResult = "Failed to connect to node";
}
else{
transferResult = "Network Error: Attaching new address failed or Transaction failed";
}
}
if (e instanceof IllegalAccessError) {
transferResult = "Local POW needs to be enabled";
}
@ -116,14 +144,12 @@ public class WalletTransferRequest extends AsyncTask<Void, Void, Void> {
break;
}
}
if(success){
transferResult = "Sent";
}
else{
transferResult = "Transfer not successful, check transfer status via Tangle explorer";
}
}
else{
transferResult = "Transfer error: Send Response not received";

View File

@ -1,8 +1,13 @@
package com.flashwifi.wifip2p.negotiation;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.util.Log;
import com.flashwifi.wifip2p.R;
import com.flashwifi.wifip2p.datastore.PeerStore;
import com.flashwifi.wifip2p.protocol.NegotiationFinalization;
import com.flashwifi.wifip2p.protocol.NegotiationOffer;
@ -11,6 +16,7 @@ import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import java.io.IOException;
import java.lang.reflect.Method;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
@ -34,7 +40,12 @@ public class Negotiator {
// consumer as in consumer-hotspot
private boolean isConsumer;
String mac = null;
String peer_mac_address = null;
private Gson gson;
private SharedPreferences prefs;
private Context context;
public enum ConsumerState {
INITIAL,
@ -59,18 +70,30 @@ public class Negotiator {
ERROR
}
public Negotiator(boolean isConsumer, String ownMacAddress) {
private void sendUpdateUIBroadcastWithMessage(String message, String snd_message){
Intent local = new Intent();
local.putExtra("message", message);
local.putExtra("snd_message", snd_message);
local.setAction("com.flashwifi.wifip2p.update_ui");
context.sendBroadcast(local);
}
public Negotiator(boolean isConsumer, String ownMacAddress, SharedPreferences prefs, Context context) {
this.isConsumer = isConsumer;
gson = new GsonBuilder().create();
this.ownMacAddress = ownMacAddress;
this.prefs = prefs;
this.context = context;
Log.d(TAG, "Negotiator: " + ownMacAddress);
}
public String workAsClient(String serverIPAddress) {
public NegotiationReturn workAsClient(String serverIPAddress) {
this.isClient = true;
String success = null;
Socket socket = null;
NegotiationReturn negReturn;
int code = 0;
boolean restartAfterwards = false;
try {
// create client socket that connects to server
@ -87,13 +110,23 @@ public class Negotiator {
// Whether we want to provide a hotspot or use one
if (isConsumer) {
success = runConsumerProtocol(serverIPAddress);
negReturn = runConsumerProtocol(serverIPAddress);
} else {
success = runHotspotProtocol(serverIPAddress);
negReturn = runHotspotProtocol(serverIPAddress);
}
mac = negReturn.mac;
restartAfterwards = negReturn.restartAfterwards;
code = negReturn.code;
} catch (SocketTimeoutException ste) {
Log.d(TAG, "workAsServer: ### Timed out after 1 seconds");
mac = null;
restartAfterwards = true;
code = R.string.err_timeout;
Log.d(TAG, "workAsServer: ### Timed out");
} catch (IOException e) {
mac = null;
restartAfterwards = true;
code = R.string.err_io_exception;
Log.d("", e.getMessage());
} finally {
if (socket != null) {
@ -104,16 +137,19 @@ public class Negotiator {
}
}
}
return success;
return new NegotiationReturn(code, mac, restartAfterwards);
}
public String workAsServer() {
public NegotiationReturn workAsServer() {
// this device is the socket server
this.isClient = false;
String peer_mac_address = null;
peer_mac_address = null;
ServerSocket serverSocket = null;
Socket socket = null;
int code = 0;
NegotiationReturn negReturn;
boolean restartAfterwards = false;
try {
// use the port to start
@ -131,28 +167,36 @@ public class Negotiator {
// WAIT FOR CLIENT
String hello = socketWrapper.getLine();
if (hello == null) {
error(0, "no hello received");
return null;
if (hello == null || hello.contains("java.net.SocketException")) {
return error(R.string.no_hello_received, true);
}
// Check: Is the peer in the same role as we are
// server and server or client and client MAKES NO SENSE
if (hello.contains("SERVER") && !isClient || hello.contains("CLIENT") && isClient){
error(1, "Pairing roles are broken");
return null;
return error(R.string.err_pairing_roles_broken, true);
}
// Whether we want to provide a hotspot or use one
if (isConsumer) {
peer_mac_address = runConsumerProtocol(socketWrapper.getClientAddress().getHostAddress());
negReturn = runConsumerProtocol(socketWrapper.getClientAddress().getHostAddress());
} else {
peer_mac_address = runHotspotProtocol(socketWrapper.getClientAddress().getHostAddress());
negReturn = runHotspotProtocol(socketWrapper.getClientAddress().getHostAddress());
}
peer_mac_address = negReturn.mac;
code = negReturn.code;
restartAfterwards = negReturn.restartAfterwards;
} catch (SocketTimeoutException ste) {
Log.d(TAG, "workAsServer: ### Timed out after 1 seconds");
Log.d(TAG, "workAsServer: ### Timed out");
code = R.string.err_timeout;
peer_mac_address = null;
restartAfterwards = true;
} catch (IOException e) {
Log.d("", e.getMessage());
Log.d(TAG, e.getMessage());
code = R.string.err_io_exception;
peer_mac_address = null;
restartAfterwards = true;
} finally {
if (socket != null) {
try {
@ -168,19 +212,17 @@ public class Negotiator {
e.printStackTrace();
}
}
}
return peer_mac_address;
return new NegotiationReturn(code, peer_mac_address, restartAfterwards);
}
private String runConsumerProtocol(String ipAddress) throws IOException {
private NegotiationReturn runConsumerProtocol(String ipAddress) throws IOException {
consumer_state = ConsumerState.WAIT_FOR_OFFER;
// RECEIVE OFFER
String offerString = socketWrapper.getLine();
if (offerString == null) {
error(2, "No offer received");
return null;
if (offerString == null || offerString.contains("java.net.SocketException")) {
return error(R.string.err_no_offer_received, true);
}
// CHECK OFFER
@ -190,26 +232,49 @@ public class Negotiator {
// Write offer to the PeerStore
PeerStore.getInstance().setLatestOffer(otherMac, offer);
// ToDo: implement accept or deny logic
if (!true) {
error(3, "Offer not acceptable");
return null;
// accept or deny logic
boolean agree = true;
int disagree_reason = 0;
int iotaPerMegabyte = Integer.valueOf(prefs.getString("edit_text_buy_price", "-1"));
if (iotaPerMegabyte < 0) {
return error(R.string.err_buy_price_bad_setting, false);
}
if (offer.getIotaPerMegabyte() > iotaPerMegabyte) {
agree = false;
disagree_reason = R.string.err_price_too_high;
}
int hotspot_max_minutes = offer.getMaxMinutes();
int hotspot_min_minutes = offer.getMinMinutes();
int client_roaming_minutes = Integer.valueOf(prefs.getString("edit_text_client_minutes", "-1"));
if (client_roaming_minutes < 0) {
return error(R.string.err_client_minutes_bad_setting, false);
}
if (client_roaming_minutes < hotspot_min_minutes || client_roaming_minutes > hotspot_max_minutes) {
agree = false;
disagree_reason = R.string.err_client_minutes_not_acceptable_for_hotspot;
}
// SEND NegotiationAnswer
// ToDo: where shall the input come from?
NegotiationOfferAnswer answer = new NegotiationOfferAnswer(true, 10, ownMacAddress);
NegotiationOfferAnswer answer = new NegotiationOfferAnswer(agree, client_roaming_minutes, ownMacAddress);
PeerStore.getInstance().setLatestOfferAnswer(otherMac, answer);
String answerString = gson.toJson(answer);
socketWrapper.sendLine(answerString);
if (!agree) {
return error(disagree_reason, false);
}
// WAIT FOR PASSWORD and hostname
consumer_state = ConsumerState.WAIT_FOR_PASSWORD;
String finalizationString = socketWrapper.getLine();
if (finalizationString == null) {
error(4, "No finalization received");
return null;
if (finalizationString == null || finalizationString.contains("java.net.SocketException")) {
return error(R.string.err_no_finalization_received, true);
} else if (answerString.equals("BYE")) {
return error(R.string.err_peer_quit, false);
}
NegotiationFinalization finalization = gson.fromJson(finalizationString, NegotiationFinalization.class);
@ -224,16 +289,27 @@ public class Negotiator {
// End
socketWrapper.close();
return otherMac;
return new NegotiationReturn(0, otherMac, false);
}
private String runHotspotProtocol(String ipAddress) throws IOException {
private NegotiationReturn runHotspotProtocol(String ipAddress) throws IOException {
// CHECK_CLIENT_REQUEST
hotspot_state = HotspotState.CHECK_CLIENT_REQUEST;
// send offer
int iotaPerMegabyte = (int) (Math.random() * (1000 - 10)) + 10;
NegotiationOffer offer = new NegotiationOffer(1, 100, iotaPerMegabyte, ownMacAddress);
int iotaPerMegabyte = Integer.valueOf(prefs.getString("edit_text_sell_price", "-1"));
if (iotaPerMegabyte < 0) {
return error(R.string.err_sell_price_bad_setting, false);
}
int minMinutes = Integer.valueOf(prefs.getString("edit_text_sell_min_minutes", "-1"));
if (minMinutes < 0) {
return error(R.string.err_min_minutes_bad_setting, false);
}
int maxMinutes = Integer.valueOf(prefs.getString("edit_text_sell_max_minutes", "-1"));
if (maxMinutes < 0) {
return error(R.string.err_max_minutes_bad_setting, false);
}
NegotiationOffer offer = new NegotiationOffer(minMinutes, maxMinutes, iotaPerMegabyte, ownMacAddress);
String offerString = gson.toJson(offer);
socketWrapper.sendLine(offerString);
@ -242,14 +318,16 @@ public class Negotiator {
hotspot_state = HotspotState.WAIT_FOR_ANSWER;
String answerString = socketWrapper.getLine();
if (answerString == null) {
error(8, "No answer received");
return null;
if (answerString == null || answerString.contains("java.net.SocketException")) {
return error(R.string.err_no_answer_received, true);
} else if (answerString.equals("BYE")) {
return error(R.string.err_peer_quit, false);
}
// Parse the answer
NegotiationOfferAnswer answer = gson.fromJson(answerString, NegotiationOfferAnswer.class);
String otherMac = answer.getConsumerMac();
peer_mac_address = otherMac;
PeerStore.getInstance().setLatestOffer(otherMac, offer);
PeerStore.getInstance().setLatestOfferAnswer(otherMac, answer);
@ -257,8 +335,11 @@ public class Negotiator {
hotspot_state = HotspotState.CHECK_ANSWER;
if (!answer.isAgreeToConditions()) {
error(5, "Client does not agree to conditions");
return null;
return error(R.string.err_client_does_not_agree, false);
}
if (answer.getDuranceInMinutes() > maxMinutes || answer.getDuranceInMinutes() < minMinutes) {
return error(R.string.err_client_minutes_out_of_bounds, false);
}
// CHECK_ITP
@ -266,7 +347,6 @@ public class Negotiator {
// if (!true) {
// writeError(0, "");
// server_state = NegotiationServerTask.State.ERROR;
// // ToDo: Error handling
// }
// GENERATE_PASSWORD and hotspot name
@ -274,11 +354,20 @@ public class Negotiator {
int min = 100000000;
int max = 999999999;
String password = Integer.toString(ThreadLocalRandom.current().nextInt(min, max + 1));
String hotspotName = "Iotify-"+Integer.toString(ThreadLocalRandom.current().nextInt(100, 10000));;
String hotspotName = "Iotify-"+Integer.toString(ThreadLocalRandom.current().nextInt(100, 10000));
// send password and hotspot name
// ToDo: get depositAddressFlashChannel from SharedPreferences
// ToDo: get the bandwidth of the hotspot
// ToDo: create initial flash object
double bandwidth = 0.1; // megabyte per second;
int max_data_volume_megabytes = (int) (answer.getDuranceInMinutes() * bandwidth);
int max_iota_transferred = max_data_volume_megabytes * offer.getIotaPerMegabyte();
max_iota_transferred = 10;
String rootAddress = "JZWUMRUEYFJOCDDRZCNIIMDZSX9LWMITNMDIAIUJKUV9LVDLSICDABFYTTBZFGEBJOADDN9WZ9IJJJD9DXRJRR9TOW";
// send the most important message to the user
NegotiationFinalization finalization = new NegotiationFinalization(hotspotName, password,
"Address", 0, 0, "");
rootAddress, max_iota_transferred, max_iota_transferred, "<flashObj>");
PeerStore.getInstance().setLatestFinalization(otherMac, finalization);
String finalizationString = gson.toJson(finalization);
@ -296,20 +385,46 @@ public class Negotiator {
socketWrapper.close();
return otherMac;
return new NegotiationReturn(0, otherMac, false);
}
// ------------------------
// HELPER METHODS BELOW
// ------------------------
private void error(int code, String msg) throws IOException {
Log.d(TAG, "error: " + msg);
private NegotiationReturn error(int err_no, boolean restartAfterwards) throws IOException {
String str = context.getString(err_no);
Log.d(TAG, "error: " + str);
if (isConsumer) {
consumer_state = ConsumerState.ERROR;
} else {
hotspot_state = HotspotState.ERROR;
}
String macAdd = (restartAfterwards) ? null : this.peer_mac_address;
sendUpdateUIBroadcastWithMessage("error", str);
if (this.peer_mac_address != null) {
PeerStore.getInstance().setErrorMessage(this.peer_mac_address, str);
}
if (!restartAfterwards) {
try {
socketWrapper.sendLine("BYE");
} catch (Exception e) {
e.printStackTrace();
}
}
socketWrapper.close();
return new NegotiationReturn(err_no, macAdd, restartAfterwards);
}
public class NegotiationReturn {
public int code;
public String mac;
public boolean restartAfterwards;
public NegotiationReturn(int code, String mac, boolean restartAfterwards) {
this.mac = mac;
this.code = code;
this.restartAfterwards = restartAfterwards;
}
}
}

View File

@ -3,6 +3,7 @@ package com.flashwifi.wifip2p.protocol;
public class BillingOpenChannel {
private int totalMegabytes;
private int totalMinutes;
private int iotaPerMegabyte;
private int timeoutMinutesClient;
private String clientRefundAddress;
@ -10,8 +11,10 @@ public class BillingOpenChannel {
private String[] clientDigests;
public BillingOpenChannel(int totalMegabytes, int iotaPerMegabyte, String clientRefundAddress,
int treeDepth, String[] clientDigests, int timeoutMinutesClient) {
int treeDepth, String[] clientDigests, int timeoutMinutesClient,
int totalMinutes) {
this.totalMegabytes = totalMegabytes;
this.totalMinutes = totalMinutes;
this.iotaPerMegabyte = iotaPerMegabyte;
this.clientRefundAddress = clientRefundAddress;
this.treeDepth = treeDepth;
@ -42,4 +45,8 @@ public class BillingOpenChannel {
public String[] getClientDigests() {
return clientDigests;
}
public int getTotalMinutes() {
return totalMinutes;
}
}

View File

@ -6,6 +6,8 @@ public class NegotiationFinalization {
private String hotspotName;
private String hotspotPassword;
private String depositAddressFlashChannel;
private String clientRefundAddress;
private String hotspotRefundAddress;
private int depositServerFlashChannelInIota;
private int depositClientFlashChannelInIota;
private String flashObject;
@ -27,4 +29,28 @@ public class NegotiationFinalization {
public String getHotspotPassword() {
return hotspotPassword;
}
public String getDepositAddressFlashChannel() {
return depositAddressFlashChannel;
}
public int getDepositServerFlashChannelInIota() {
return depositServerFlashChannelInIota;
}
public int getDepositClientFlashChannelInIota() {
return depositClientFlashChannelInIota;
}
public String getFlashObject() {
return flashObject;
}
public String getClientRefundAddress() {
return clientRefundAddress;
}
public String getHotspotRefundAddress() {
return hotspotRefundAddress;
}
}

View File

@ -60,14 +60,55 @@
android:clickable="false"
android:text="Flash channel" />
<Button
android:id="@+id/stopRoamingButton"
<CheckBox
android:id="@+id/channelFunded"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="STOP"
android:layout_marginLeft="15dp"
android:layout_marginRight="15dp"
android:layout_marginBottom="10dp" />
android:layout_marginBottom="10dp"
android:checked="false"
android:clickable="false"
android:text="Channel funded" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginLeft="15dp"
android:layout_marginRight="15dp"
android:layout_marginBottom="10dp" >
<Button
android:id="@+id/stopRoamingButton"
android:layout_width="250dp"
android:layout_height="wrap_content"
android:text="STOP"
/>
<ProgressBar
android:id="@+id/stopProgressBar"
android:layout_marginTop="5dp"
android:layout_width="wrap_content"
android:layout_height="35dp"
android:indeterminate="true"
android:visibility="gone"
/>
</LinearLayout>
<TextView
android:id="@+id/stopText"
android:gravity="center"
android:layout_margin="5dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/channelClosed"
android:visibility="gone"/>
</LinearLayout>
@ -75,6 +116,49 @@
</android.support.v7.widget.CardView>
<android.support.v7.widget.CardView
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:id="@+id/card_view_tangle_attachment"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="15dp"
android:layout_gravity="center"
android:visibility="gone"
card_view:cardCornerRadius="4dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_margin="15dp">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Retransfer deposits"
android:textSize="20sp" />
<ProgressBar
android:id="@+id/progressbarRetransfer"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:max="100"
android:progress="5"
/>
<TextView
android:id="@+id/retransferText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/initRetransfer"/>
</LinearLayout>
</android.support.v7.widget.CardView>
<android.support.v7.widget.CardView
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:id="@+id/card_view_overview"
@ -98,14 +182,14 @@
android:textSize="20sp" />
<TextView
<ProgressBar
android:id="@+id/progressbarMegabytes"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="15dp"
android:layout_marginEnd="15dp"
android:id="@+id/summaryMinutes"
android:text="0 minutes open"
android:textSize="15sp" />
android:layout_marginLeft="15dp"
android:layout_marginRight="15dp"
/>
<TextView
android:id="@+id/summaryMegabytes"
@ -116,25 +200,44 @@
android:text="0/0 Megabytes"
android:textSize="15sp" />
<ProgressBar
android:id="@+id/progressbarDurance"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="15dp"
android:layout_marginRight="15dp"
android:layout_marginTop="20dp"
/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="15dp"
android:layout_marginEnd="15dp"
android:id="@+id/summaryMinutes"
android:text="0/0 seconds"
android:textSize="15sp" />
<ProgressBar
android:id="@+id/progressbarIota"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="15dp"
android:layout_marginRight="15dp"
android:layout_marginTop="20dp"
/>
<TextView
android:id="@+id/summaryIota"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="15dp"
android:layout_marginEnd="15dp"
android:text="0 Iota transferred"
android:textSize="15sp" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="15dp"
android:layout_marginEnd="15dp"
android:text="0.1 Miota still locked"
android:text="0/0 Iota transferred"
android:textSize="15sp"
android:layout_marginBottom="20dp"/>
android:paddingBottom="20dp"/>
</LinearLayout>
@ -142,6 +245,8 @@
</LinearLayout>

View File

@ -19,7 +19,7 @@
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:popupTheme="@style/AppTheme.NoActionBar.PopupOverlay">
<Switch
<!--<Switch
android:layout_width="wrap_content"
android:layout_height="?attr/actionBarSize"
android:layout_gravity="end"
@ -27,7 +27,7 @@
android:checked="false"
android:hint="@string/wifi_p2p_discovery"
android:width="120dp"
android:id="@+id/wifiSwitch"/>
android:id="@+id/wifiSwitch"/>-->
</android.support.v7.widget.Toolbar>

View File

@ -12,6 +12,7 @@
android:id="@+id/content_frame"
android:layout_width="match_parent"
android:layout_height="match_parent">
</FrameLayout>

View File

@ -9,6 +9,7 @@
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:paddingTop="25dp"
android:text="@string/hotspotIntroduction"
android:textSize="20sp" />
@ -18,13 +19,15 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="@string/startAP" />
android:textOn="@string/stopAP"
android:textOff="@string/startAPText" />
<ProgressBar
android:id="@+id/progressbarAP"
style="?android:attr/progressBarStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="25dp"
android:visibility="invisible" />
<TextView
@ -32,6 +35,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:visibility="invisible"
android:text="0 peers"
android:textSize="30sp" />

View File

@ -34,7 +34,8 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="left"
android:layout_marginRight="50dp"
android:layout_weight="1"
android:layout_marginRight="20dp"
android:text="Device name"
android:textAppearance="@style/TextAppearance.AppCompat.Headline" />
@ -61,21 +62,14 @@
<TextView android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:textColor="#000000"
android:gravity="right"
android:layout_weight="1"
android:id="@+id/description"
android:text="description"
android:layout_marginRight="20dp"/>
<TextView android:textColor="#000000"
android:id="@+id/ipAddr"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="ipAddr"
android:layout_marginRight="20dp"/>
<TextView android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_weight="1"
android:layout_weight="0"
android:textColor="#000000"
android:id="@+id/iotaPrice"
android:text="iotaPrice" />
@ -83,6 +77,15 @@
</LinearLayout>
<ProgressBar
android:id="@+id/progressConnection"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:indeterminate="true"
android:visibility="gone"
/>

View File

@ -12,10 +12,10 @@
android:id="@+id/nav_start"
android:icon="@drawable/icon_tethering_on"
android:title="@string/menuStartHotspot" />
<item
<!-- <item
android:id="@+id/nav_itp"
android:icon="@drawable/ic_highlight_black"
android:title="@string/initialTrustPayment" />
android:title="@string/initialTrustPayment" />-->
</group>
@ -32,12 +32,12 @@
</menu>
</item>
<item android:title="Communicate">
<item android:title="Conditions">
<menu>
<item
<!-- <item
android:id="@+id/nav_conditions"
android:icon="@drawable/ic_compare_arrows"
android:title="@string/navConditions" />
android:title="@string/navConditions" />-->
<item
android:id="@+id/nav_settings"
android:icon="@drawable/ic_menu_manage"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.7 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.5 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 4.6 KiB

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="protocolPrivateTestnetNode">http</string>
<string name="hostPrivateTestnetNode">87.118.96.200</string>
<string name="portPrivateTestnetNode">14700</string>
<string name="generatorPrivateTestnetNode">http://87.118.96.200:3000/</string>
<string name="protocolPublicTestnetNode">https</string>
<string name="hostPublicTestnetNode">testnet140.tangle.works</string>
<string name="portPublicTestnetNode">443</string>
<string name="generatorPublicTestnetNode">https://hackseeds.tangle.works</string>
<string name="protocolDefaultMainnetNode">http</string>
<string name="hostDefaultMainnetNode">node.iotawallet.info</string>
<string name="portDefaultMainnetNode">14265</string>
</resources>

View File

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="err_no_finalization_received">No finalization received</string>
<string name="err_pairing_roles_broken">Pairing roles are broken</string>
<string name="no_hello_received">No hello received</string>
<string name="err_no_offer_received">No offer received</string>
<string name="err_buy_price_bad_setting">Buy price bad setting</string>
<string name="err_price_too_high">Price too high</string>
<string name="err_client_minutes_bad_setting">Client minutes bad setting</string>
<string name="err_client_minutes_not_acceptable_for_hotspot">Client minutes not acceptable for hotspot</string>
<string name="err_sell_price_bad_setting">Sell price bad setting</string>
<string name="err_min_minutes_bad_setting">Min minutes bad setting</string>
<string name="err_max_minutes_bad_setting">Max minutes bad setting</string>
<string name="err_no_answer_received">No answer received</string>
<string name="err_client_does_not_agree">Client does not agree to conditions</string>
<string name="err_client_minutes_out_of_bounds">Client minutes is out of bounds</string>
<string name="err_timeout">Timeout</string>
<string name="err_io_exception">IO Exception</string>
<string name="err_peer_quit">Peer quit the conversation</string>
</resources>

View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string-array name="securityPref" >
<item>1</item>
<item>2</item>
<item>3</item>
</string-array>
<string-array name="networkTimeoutPref" >
<item>15 seconds</item>
<item>30 seconds</item>
<item>1 minute</item>
<item>3 minutes</item>
<item>No timeout</item>
</string-array>
<string-array name="unitsPref" >
<item>Iota (i)</item>
<item>Kilo Iota (Ki)</item>
<item>Mega Iota (Mi)</item>
<item>Giga Iota (Gi)</item>
<item>Tera Iota (Ti)</item>
<item>Peta Iota (Pi)</item>
</string-array>
</resources>

View File

@ -1,5 +1,6 @@
<resources>
<string name="app_name">WifiP2P</string>
<string name="app_version">1.0</string>
<string name="title_activity_scrolling">ScrollingActivity</string>
<string name="action_settings">Settings</string>
<string name="wifi_direct">Wifi Direct Chat</string>
@ -64,5 +65,11 @@
<string name="startSearch">Start Search</string>
<string name="roaming_title">Roaming (This is your hotspot)</string>
<string name="roaming_title_client">Roaming (You are consuming)</string>
<string name="channelClosed">The payment channel was closed.</string>
<string name="initRetransfer">Initializing retransfer</string>
<string name="welcome">Welcome to the Wifi Iota Hotspot App</string>
<string name="notification_doing_nothing">Currently doing nothing</string>
<string name="stopAP">Stop Hotspot</string>
<string name="startAPText">Start Hotspot</string>
</resources>

View File

@ -0,0 +1,158 @@
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<PreferenceCategory
android:title="WiFi"
android:key="pref_key_wifi_settings"
android:elevation="10dp">
<Preference
android:divider="@null"
android:dividerHeight="0dp"
android:key="pref_key_reset_data_usage"
android:title="Reset data usage"/>
</PreferenceCategory>
<PreferenceCategory
android:title="IOTA"
android:elevation="10dp"
android:animateLayoutChanges="true"
android:key="pref_key_IOTA_settings">
<ListPreference
android:key="pref_key_security"
android:divider="@null"
android:dividerHeight="0dp"
android:defaultValue="2"
android:entries="@array/securityPref"
android:entryValues="@array/securityPref"
android:title="Security pk/address" />
<ListPreference
android:key="pref_key_network_timeout"
android:entries="@array/networkTimeoutPref"
android:entryValues="@array/networkTimeoutPref"
android:title="Network timeout" />
<ListPreference
android:key="pref_key_units"
android:entries="@array/unitsPref"
android:entryValues="@array/unitsPref"
android:title="Units" />
<SwitchPreference
android:defaultValue="true"
android:key="pref_key_switch_testnet"
android:title="Testnet" />
<SwitchPreference
android:defaultValue="true"
android:key="pref_key_switch_testnet_private"
android:title="Private testnet (recommended)" />
<Preference
android:divider="@null"
android:dividerHeight="0dp"
android:key="pref_key_testnet_fund_add"
android:title="Add 2000i testnet"/>
</PreferenceCategory>
<PreferenceCategory
android:title="Hotspot payment conditions"
android:elevation="10dp"
android:key="pref_key_payment_settings">
<EditTextPreference
android:defaultValue="10"
android:key="edit_text_sell_price"
android:inputType="number"
android:selectAllOnFocus="true"
android:singleLine="true"
android:title="Sell price" />
<EditTextPreference
android:defaultValue="15"
android:inputType="number"
android:key="edit_text_sell_min_minutes"
android:selectAllOnFocus="true"
android:singleLine="true"
android:title="Minimum sell duration (minutes)" />
<EditTextPreference
android:defaultValue="100"
android:key="edit_text_sell_max_minutes"
android:inputType="number"
android:selectAllOnFocus="true"
android:singleLine="true"
android:title="Maximum sell duration (minutes)" />
</PreferenceCategory>
<PreferenceCategory
android:title="Client payment conditions"
android:elevation="10dp"
android:key="pref_key_payment_settings">
<EditTextPreference
android:defaultValue="15"
android:key="edit_text_buy_price"
android:inputType="number"
android:selectAllOnFocus="true"
android:singleLine="true"
android:title="Max buy price" />
<EditTextPreference
android:defaultValue="60"
android:key="edit_text_client_minutes"
android:inputType="number"
android:selectAllOnFocus="true"
android:singleLine="true"
android:title="Client roaming duration" />
</PreferenceCategory>
<PreferenceCategory
android:title="Wallet"
android:elevation="10dp"
android:key="pref_key_wallet_settings">
<Preference
android:key="pref_key_reset_password"
android:title="Reset Password"/>
<Preference
android:key="pref_key_reset_wallet"
android:title="Reset Wallet"/>
</PreferenceCategory>
<PreferenceCategory
android:title="About"
android:key="pref_key_about"
android:elevation="10dp">
<Preference
android:divider="@null"
android:dividerHeight="0dp"
android:key="pref_key_reset_version"
android:title="@string/app_version"/>
<Preference
android:divider="@null"
android:dividerHeight="0dp"
android:key="pref_key_license"
android:title="License"/>
<Preference
android:divider="@null"
android:dividerHeight="0dp"
android:key="pref_key_agreement"
android:title="Agreement"/>
</PreferenceCategory>
</PreferenceScreen>