1
mirror of https://github.com/m2049r/xmrwallet synced 2025-09-06 02:27:11 +02:00

Compare commits

...

7 Commits

Author SHA1 Message Date
m2049r
60a7b15700 new version for fixed malloc (83dcd65) 2018-04-03 11:51:14 +02:00
m2049r
df2ff8b3b7 correct toolbar colour for testnet (#218) 2018-04-02 13:02:00 +02:00
m2049r
da8c8f80f1 new version for m2049r/monero 7e97e11 (#217) 2018-04-02 12:14:55 +02:00
m2049r
eda3de11fe added zxcvbn4j license (#216) 2018-04-01 13:23:03 +02:00
m2049r
7d7de14827 new version id for monero PR#3526 (#215) 2018-03-30 14:12:17 +02:00
m2049r
1c709da92c Update FAQ.md 2018-03-29 23:00:39 +02:00
m2049r
a9092497b2 changes for monero v0.12 (#214)
* new version id & name
* witness checksums
* build docs updated for v0.12
* remove binaries
* setenv HOME for ringdb to 'monero' in shared storage
* min ringsize 7
* remove boost_locale and zmq from build - don't need them for wallet_api
* splits for all archs
* throw IndexOutOfBounds in case the TX is empty
* donate, you ungrateful bastards! (removed donations to make google happy)
2018-03-29 22:35:31 +02:00
165 changed files with 951 additions and 549 deletions

View File

@@ -60,9 +60,13 @@ set_target_properties(boost_wserialization PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/boost/lib/${ANDROID_ABI}/libboost_wserialization.a)
#############
# Monero set(libs_to_merge wallet cryptonote_core cryptonote_basic mnemonics common cncrypto ringct)
# Monero
#############
add_library(wallet_api STATIC IMPORTED)
set_target_properties(wallet_api PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libwallet_api.a)
add_library(wallet STATIC IMPORTED)
set_target_properties(wallet PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libwallet.a)
@@ -91,11 +95,9 @@ add_library(ringct STATIC IMPORTED)
set_target_properties(ringct PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libringct.a)
#####
add_library(p2p STATIC IMPORTED)
set_target_properties(p2p PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libp2p.a)
add_library(ringct_basic STATIC IMPORTED)
set_target_properties(ringct_basic PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libringct_basic.a)
add_library(blockchain_db STATIC IMPORTED)
set_target_properties(blockchain_db PROPERTIES IMPORTED_LOCATION
@@ -113,7 +115,6 @@ add_library(unbound STATIC IMPORTED)
set_target_properties(unbound PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libunbound.a)
####
add_library(epee STATIC IMPORTED)
set_target_properties(epee PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libepee.a)
@@ -122,9 +123,21 @@ add_library(blocks STATIC IMPORTED)
set_target_properties(blocks PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libblocks.a)
add_library(miniupnpc STATIC IMPORTED)
set_target_properties(miniupnpc PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libminiupnpc.a)
add_library(checkpoints STATIC IMPORTED)
set_target_properties(checkpoints PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libcheckpoints.a)
add_library(device STATIC IMPORTED)
set_target_properties(device PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libdevice.a)
add_library(multisig STATIC IMPORTED)
set_target_properties(multisig PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libmultisig.a)
add_library(version STATIC IMPORTED)
set_target_properties(version PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libversion.a)
#############
# System
@@ -137,23 +150,26 @@ include_directories( ${EXTERNAL_LIBS_DIR}/monero/include )
message(STATUS EXTERNAL_LIBS_DIR : ${EXTERNAL_LIBS_DIR})
target_link_libraries( monerujo
wallet_api
wallet
cryptonote_core
cryptonote_basic
mnemonics
ringct
ringct_basic
common
cncrypto
blockchain_db
lmdb
easylogging
unbound
p2p
epee
blocks
miniupnpc
checkpoints
device
multisig
version
boost_chrono
boost_date_time

View File

@@ -8,8 +8,8 @@ android {
applicationId "com.m2049r.xmrwallet"
minSdkVersion 21
targetSdkVersion 25
versionCode 74
versionName "1.3.14 'Satoshis Dream'"
versionCode 86
versionName "1.4.6 'Monero Spedner'"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
externalNativeBuild {
cmake {
@@ -42,7 +42,7 @@ android {
enable true
reset()
include 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64'
universalApk false
universalApk true
}
}
@@ -104,5 +104,7 @@ dependencyVerification {
'com.google.zxing:core:bba7724e02a997cec38213af77133ee8e24b0d5cf5fa7ecbc16a4fa93f11ee0d',
'com.squareup.okio:okio:734269c3ebc5090e3b23566db558f421f0b4027277c79ad5d176b8ec168bb850',
'com.squareup.okhttp3:okhttp:7265adbd6f028aade307f58569d814835cd02bc9beffb70c25f72c9de50d61c4',
'com.jakewharton.timber:timber:35c22867f2673132e97e17857d36bb2fc25f5790f0425406833ed0254d62fc66',
'com.nulab-inc:zxcvbn:18d7862a6abd2705defec478d77dedadf8f3bb7cf811df22995494f05485785f',
]
}

File diff suppressed because it is too large Load Diff

View File

@@ -386,7 +386,7 @@ public class GenerateFragment extends Fragment {
private boolean checkAddress() {
String address = etWalletAddress.getEditText().getText().toString();
boolean ok = Wallet.isAddressValid(address, WalletManager.getInstance().isTestNet());
boolean ok = Wallet.isAddressValid(address);
if (!ok) {
etWalletAddress.setError(getString(R.string.generate_check_address));
} else {

View File

@@ -34,6 +34,7 @@ import android.widget.ScrollView;
import android.widget.TextView;
import android.widget.Toast;
import com.m2049r.xmrwallet.model.NetworkType;
import com.m2049r.xmrwallet.widget.Toolbar;
import com.m2049r.xmrwallet.model.Wallet;
import com.m2049r.xmrwallet.model.WalletManager;
@@ -81,7 +82,7 @@ public class GenerateReviewFragment extends Fragment {
bAccept = (Button) view.findViewById(R.id.bAccept);
boolean testnet = WalletManager.getInstance().isTestNet();
boolean testnet = WalletManager.getInstance().getNetworkType() != NetworkType.NetworkType_Mainnet;
tvWalletMnemonic.setTextIsSelectable(testnet);
tvWalletSpendKey.setTextIsSelectable(testnet);
@@ -185,6 +186,7 @@ public class GenerateReviewFragment extends Fragment {
name = wallet.getName();
status = wallet.getStatus();
if (status != Wallet.Status.Status_Ok) {
Timber.e(wallet.getErrorString());
if (closeWallet) wallet.close();
return false;
}

File diff suppressed because it is too large Load Diff

View File

@@ -45,6 +45,7 @@ import android.widget.Toast;
import com.m2049r.xmrwallet.dialog.HelpFragment;
import com.m2049r.xmrwallet.layout.WalletInfoAdapter;
import com.m2049r.xmrwallet.model.NetworkType;
import com.m2049r.xmrwallet.model.WalletManager;
import com.m2049r.xmrwallet.util.Helper;
import com.m2049r.xmrwallet.util.NodeList;
@@ -81,11 +82,11 @@ public class LoginFragment extends Fragment implements WalletInfoAdapter.OnInter
File getStorageRoot();
boolean onWalletSelected(String wallet, String daemon, boolean testnet);
boolean onWalletSelected(String wallet, String daemon);
void onWalletDetails(String wallet, boolean testnet);
void onWalletDetails(String wallet);
void onWalletReceive(String wallet, boolean testnet);
void onWalletReceive(String wallet);
void onWalletRename(String name);
@@ -93,14 +94,16 @@ public class LoginFragment extends Fragment implements WalletInfoAdapter.OnInter
void onWalletArchive(String walletName);
void onAddWallet(boolean testnet, String type);
void onAddWallet(String type);
void showNet(boolean testnet);
void showNet();
void setToolbarButton(int type);
void setTitle(String title);
void setNetworkType(NetworkType networkType);
}
@Override
@@ -126,8 +129,8 @@ public class LoginFragment extends Fragment implements WalletInfoAdapter.OnInter
super.onResume();
Timber.d("onResume()");
activityCallback.setTitle(null);
activityCallback.setToolbarButton(Toolbar.BUTTON_DONATE);
activityCallback.showNet(isTestnet());
activityCallback.setToolbarButton(Toolbar.BUTTON_CREDITS);
activityCallback.showNet();
}
@Override
@@ -244,13 +247,13 @@ public class LoginFragment extends Fragment implements WalletInfoAdapter.OnInter
// Callbacks from WalletInfoAdapter
@Override
public void onInteraction(final View view, final WalletManager.WalletInfo infoItem) {
String x = isTestnet() ? "9A-" : "4-";
if (x.indexOf(infoItem.address.charAt(0)) < 0) {
String addressPrefix = addressPrefix();
if (addressPrefix.indexOf(infoItem.address.charAt(0)) < 0) {
Toast.makeText(getActivity(), getString(R.string.prompt_wrong_net), Toast.LENGTH_LONG).show();
return;
}
if (activityCallback.onWalletSelected(infoItem.name, getDaemon(), isTestnet())) {
if (activityCallback.onWalletSelected(infoItem.name, getDaemon())) {
savePrefs();
}
}
@@ -279,11 +282,24 @@ public class LoginFragment extends Fragment implements WalletInfoAdapter.OnInter
return true;
}
private String addressPrefix() {
switch (WalletManager.getInstance().getNetworkType()) {
case NetworkType_Testnet:
return "9A-";
case NetworkType_Mainnet:
return "4-";
case NetworkType_Stagenet:
return "5-";
default:
throw new IllegalStateException("Unsupported Network: " + WalletManager.getInstance().getNetworkType());
}
}
private void filterList() {
displayedList.clear();
String x = isTestnet() ? "9A" : "4";
String addressPrefix = addressPrefix();
for (WalletManager.WalletInfo s : walletList) {
if (x.indexOf(s.address.charAt(0)) >= 0) displayedList.add(s);
if (addressPrefix.indexOf(s.address.charAt(0)) >= 0) displayedList.add(s);
}
}
@@ -313,11 +329,11 @@ public class LoginFragment extends Fragment implements WalletInfoAdapter.OnInter
}
private void showInfo(@NonNull String name) {
activityCallback.onWalletDetails(name, isTestnet());
activityCallback.onWalletDetails(name);
}
private void showReceive(@NonNull String name) {
activityCallback.onWalletReceive(name, isTestnet());
activityCallback.onWalletReceive(name);
}
@Override
@@ -329,29 +345,31 @@ public class LoginFragment extends Fragment implements WalletInfoAdapter.OnInter
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.list_menu, menu);
menu.findItem(R.id.action_testnet).setChecked(isTestnet());
menu.findItem(R.id.action_testnet).setChecked(testnetCheckMenu);
super.onCreateOptionsMenu(menu, inflater);
}
private boolean testnet = BuildConfig.DEBUG;
private boolean testnetCheckMenu = BuildConfig.DEBUG;
boolean isTestnet() {
return testnet;
}
//boolean isTestnet() {
// return testnet;
//}
public boolean onTestnetMenuItem() {
boolean lastState = testnet;
boolean lastState = testnetCheckMenu;
setNet(!lastState, true); // set and save
return !lastState;
}
public void setNet(boolean testnet, boolean save) {
this.testnet = testnet;
activityCallback.showNet(testnet);
public void setNet(boolean testnetChecked, boolean save) {
this.testnetCheckMenu = testnetChecked;
NetworkType net = testnetChecked ? NetworkType.NetworkType_Testnet : NetworkType.NetworkType_Mainnet;
activityCallback.setNetworkType(net);
activityCallback.showNet();
if (save) {
savePrefs(true); // use previous state as we just clicked it
}
if (testnet) {
if (testnetChecked) {
setDaemon(daemonTestNet);
} else {
setDaemon(daemonMainNet);
@@ -379,7 +397,7 @@ public class LoginFragment extends Fragment implements WalletInfoAdapter.OnInter
daemonMainNet = new NodeList(sharedPref.getString(PREF_DAEMON_MAINNET, PREF_DAEMONLIST_MAINNET));
daemonTestNet = new NodeList(sharedPref.getString(PREF_DAEMON_TESTNET, PREF_DAEMONLIST_TESTNET));
setNet(isTestnet(), false);
setNet(testnetCheckMenu, false);
showXmrtoEnabled = sharedPref.getBoolean(PREF_SHOW_XMRTO_ENABLED, true);
}
@@ -398,7 +416,7 @@ public class LoginFragment extends Fragment implements WalletInfoAdapter.OnInter
void savePrefs(boolean usePreviousTestnetState) {
Timber.d("SAVE / %s", usePreviousTestnetState);
// save the daemon address for the net
boolean testnet = isTestnet() ^ usePreviousTestnetState;
boolean testnet = testnetCheckMenu ^ usePreviousTestnetState;
String daemon = getDaemon();
if (testnet) {
daemonTestNet.setRecent(daemon);
@@ -484,19 +502,19 @@ public class LoginFragment extends Fragment implements WalletInfoAdapter.OnInter
case R.id.fabNew:
fabScreen.setVisibility(View.INVISIBLE);
isFabOpen = false;
activityCallback.onAddWallet(isTestnet(), GenerateFragment.TYPE_NEW);
activityCallback.onAddWallet(GenerateFragment.TYPE_NEW);
break;
case R.id.fabView:
animateFAB();
activityCallback.onAddWallet(isTestnet(), GenerateFragment.TYPE_VIEWONLY);
activityCallback.onAddWallet(GenerateFragment.TYPE_VIEWONLY);
break;
case R.id.fabKey:
animateFAB();
activityCallback.onAddWallet(isTestnet(), GenerateFragment.TYPE_KEY);
activityCallback.onAddWallet(GenerateFragment.TYPE_KEY);
break;
case R.id.fabSeed:
animateFAB();
activityCallback.onAddWallet(isTestnet(), GenerateFragment.TYPE_SEED);
activityCallback.onAddWallet(GenerateFragment.TYPE_SEED);
break;
case R.id.fabScreen:
animateFAB();

View File

@@ -300,7 +300,7 @@ public class ReceiveFragment extends Fragment {
String paymentId = etPaymentId.getEditText().getText().toString();
String xmrAmount = evAmount.getAmount();
Timber.d("%s/%s/%s", xmrAmount, paymentId, address);
if ((xmrAmount == null) || !Wallet.isAddressValid(address, WalletManager.getInstance().isTestNet())) {
if ((xmrAmount == null) || !Wallet.isAddressValid(address)) {
clearQR();
Timber.d("CLEARQR");
return;

View File

@@ -36,7 +36,7 @@ import android.widget.Toast;
import com.m2049r.xmrwallet.data.BarcodeData;
import com.m2049r.xmrwallet.data.TxData;
import com.m2049r.xmrwallet.dialog.DonationFragment;
import com.m2049r.xmrwallet.dialog.CreditsFragment;
import com.m2049r.xmrwallet.dialog.HelpFragment;
import com.m2049r.xmrwallet.fragment.send.SendAddressWizardFragment;
import com.m2049r.xmrwallet.fragment.send.SendFragment;
@@ -159,8 +159,8 @@ public class WalletActivity extends SecureActivity implements WalletFragment.Lis
case R.id.action_info:
onWalletDetails();
return true;
case R.id.action_donate:
DonationFragment.display(getSupportFragmentManager());
case R.id.action_credits:
CreditsFragment.display(getSupportFragmentManager());
return true;
case R.id.action_share:
onShareTxInfo();
@@ -213,8 +213,8 @@ public class WalletActivity extends SecureActivity implements WalletFragment.Lis
case Toolbar.BUTTON_CLOSE:
finish();
break;
case Toolbar.BUTTON_DONATE:
Toast.makeText(WalletActivity.this, getString(R.string.label_donate), Toast.LENGTH_SHORT).show();
case Toolbar.BUTTON_CREDITS:
Toast.makeText(WalletActivity.this, getString(R.string.label_credits), Toast.LENGTH_SHORT).show();
case Toolbar.BUTTON_NONE:
default:
Timber.e("Button " + type + "pressed - how can this be?");
@@ -222,12 +222,7 @@ public class WalletActivity extends SecureActivity implements WalletFragment.Lis
}
});
boolean testnet = WalletManager.getInstance().isTestNet();
if (testnet) {
toolbar.setBackgroundResource(R.color.colorPrimaryDark);
} else {
toolbar.setBackgroundResource(R.drawable.backgound_toolbar_mainnet);
}
showNet();
Fragment walletFragment = new WalletFragment();
getSupportFragmentManager().beginTransaction()
@@ -238,6 +233,23 @@ public class WalletActivity extends SecureActivity implements WalletFragment.Lis
Timber.d("onCreate() done.");
}
public void showNet() {
switch (WalletManager.getInstance().getNetworkType()) {
case NetworkType_Mainnet:
toolbar.setBackgroundResource(R.drawable.backgound_toolbar_mainnet);
break;
case NetworkType_Testnet:
toolbar.setBackgroundResource(R.color.colorPrimaryDark);
break;
case NetworkType_Stagenet:
toolbar.setBackgroundResource(R.color.colorPrimaryDark);
break;
default:
throw new IllegalStateException("Unsupported Network: " + WalletManager.getInstance().getNetworkType());
}
}
public Wallet getWallet() {
if (mBoundService == null) throw new IllegalStateException("WalletService not bound.");
return mBoundService.getWallet();
@@ -798,7 +810,7 @@ public class WalletActivity extends SecureActivity implements WalletFragment.Lis
@Override
public boolean verifyWalletPassword(String password) {
String walletPath = new File(Helper.getStorageRoot(this),
String walletPath = new File(Helper.getWalletRoot(this),
getWalletName() + ".keys").getAbsolutePath();
return WalletManager.getInstance().verifyWalletPassword(walletPath, password, true);
}

View File

@@ -19,13 +19,15 @@ package com.m2049r.xmrwallet;
import android.app.Application;
import com.m2049r.xmrwallet.util.Helper;
import timber.log.Timber;
public class XmrWalletApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
if (BuildConfig.DEBUG) {
Timber.plant(new Timber.DebugTree());
}

View File

@@ -18,6 +18,7 @@ package com.m2049r.xmrwallet.data;
import android.net.Uri;
import com.m2049r.xmrwallet.model.NetworkType;
import com.m2049r.xmrwallet.model.Wallet;
import com.m2049r.xmrwallet.model.WalletManager;
import com.m2049r.xmrwallet.util.BitcoinAddressValidator;
@@ -178,7 +179,7 @@ public class BarcodeData {
return null; // we have an amount but its not a number!
}
}
if (!BitcoinAddressValidator.validate(address, WalletManager.getInstance().isTestNet())) {
if (!BitcoinAddressValidator.validate(address)) {
Timber.d("address invalid");
return null;
}
@@ -190,7 +191,7 @@ public class BarcodeData {
if (address == null) return null;
if (!BitcoinAddressValidator.validate(address, WalletManager.getInstance().isTestNet())) {
if (!BitcoinAddressValidator.validate(address)) {
Timber.d("address invalid");
return null;
}

View File

@@ -0,0 +1,108 @@
/*
* Copyright (c) 2018 m2049r
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.m2049r.xmrwallet.data;
import com.m2049r.xmrwallet.model.NetworkType;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
public class WalletNode {
private final String name;
private final String host;
private final int port;
private final String user;
private final String password;
private final NetworkType networkType;
public WalletNode(String walletName, String daemon, NetworkType networkType) {
if ((daemon == null) || daemon.isEmpty())
throw new IllegalArgumentException("daemon is empty");
this.name = walletName;
String daemonAddress;
String a[] = daemon.split("@");
if (a.length == 1) { // no credentials
daemonAddress = a[0];
user = "";
password = "";
} else if (a.length == 2) { // credentials
String userPassword[] = a[0].split(":");
if (userPassword.length != 2)
throw new IllegalArgumentException("User:Password invalid");
user = userPassword[0];
if (!user.isEmpty()) {
password = userPassword[1];
} else {
password = "";
}
daemonAddress = a[1];
} else {
throw new IllegalArgumentException("Too many @");
}
String da[] = daemonAddress.split(":");
if ((da.length > 2) || (da.length < 1))
throw new IllegalArgumentException("Too many ':' or too few");
host = da[0];
if (da.length == 2) {
try {
port = Integer.parseInt(da[1]);
} catch (NumberFormatException ex) {
throw new IllegalArgumentException("Port not numeric");
}
} else {
switch (networkType) {
case NetworkType_Mainnet:
port = 18081;
break;
case NetworkType_Testnet:
port = 28081;
break;
case NetworkType_Stagenet:
port = 38081;
break;
default:
port = 0;
}
}
this.networkType = networkType;
}
public String getName() {
return name;
}
public String getAddress() {
return host + ":" + port;
}
public String getUsername() {
return user;
}
public String getPassword() {
return password;
}
public SocketAddress getSocketAddress() {
return new InetSocketAddress(host, port);
}
public boolean isValid() {
return !host.isEmpty();
}
}

View File

@@ -28,16 +28,14 @@ import android.text.Html;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;
import com.m2049r.xmrwallet.R;
import com.m2049r.xmrwallet.util.Helper;
public class DonationFragment extends DialogFragment {
public class CreditsFragment extends DialogFragment {
static final String TAG = "DonationFragment";
public static DonationFragment newInstance() {
return new DonationFragment();
public static CreditsFragment newInstance() {
return new CreditsFragment();
}
public static void display(FragmentManager fm) {
@@ -47,24 +45,14 @@ public class DonationFragment extends DialogFragment {
ft.remove(prev);
}
DonationFragment.newInstance().show(ft, TAG);
CreditsFragment.newInstance().show(ft, TAG);
}
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
final View view = LayoutInflater.from(getActivity()).inflate(R.layout.fragment_donation, null);
final View view = LayoutInflater.from(getActivity()).inflate(R.layout.fragment_credits, null);
((TextView) view.findViewById(R.id.tvCredits)).setText(Html.fromHtml(getString(R.string.donation_credits)));
(view.findViewById(R.id.bCopyAddress)).
setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Helper.clipBoardCopy(getActivity(), getString(R.string.label_copy_address),
((TextView) view.findViewById(R.id.tvWalletAddress)).getText().toString());
Toast.makeText(getActivity(), getString(R.string.message_copy_address), Toast.LENGTH_SHORT).show();
}
});
((TextView) view.findViewById(R.id.tvCredits)).setText(Html.fromHtml(getString(R.string.credits_text)));
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setView(view);

View File

@@ -212,7 +212,7 @@ public class SendAddressWizardFragment extends SendWizardFragment {
private boolean checkAddressNoError() {
String address = etAddress.getEditText().getText().toString();
return Wallet.isAddressValid(address)
|| BitcoinAddressValidator.validate(address, WalletManager.getInstance().isTestNet());
|| BitcoinAddressValidator.validate(address);
}
private boolean checkAddress() {
@@ -228,13 +228,13 @@ public class SendAddressWizardFragment extends SendWizardFragment {
private boolean isIntegratedAddress() {
String address = etAddress.getEditText().getText().toString();
return (address.length() == INTEGRATED_ADDRESS_LENGTH)
&& Wallet.isAddressValid(address, WalletManager.getInstance().isTestNet());
&& Wallet.isAddressValid(address);
}
private boolean isBitcoinAddress() {
String address = etAddress.getEditText().getText().toString();
if ((address.length() >= 27) && (address.length() <= 34))
return BitcoinAddressValidator.validate(address, WalletManager.getInstance().isTestNet());
return BitcoinAddressValidator.validate(address);
else
return false;
}

View File

@@ -54,7 +54,8 @@ public class SendSettingsWizardFragment extends SendWizardFragment {
TxData getTxData();
}
final static int Mixins[] = {4, 7, 12, 25}; // must match the layout XML
// Mixin = Ringsize - 1
final static int Mixins[] = {6, 9, 12, 25}; // must match the layout XML / "@array/mixin"
final static PendingTransaction.Priority Priorities[] =
{PendingTransaction.Priority.Priority_Default,
PendingTransaction.Priority.Priority_Low,

View File

@@ -137,12 +137,7 @@ public class TransactionInfoAdapter extends RecyclerView.Adapter<TransactionInfo
ivTxType.setVisibility(View.GONE); // gives us more space for the amount
}
long realAmount = infoItem.amount;
if (infoItem.isPending) {
realAmount = realAmount - infoItem.fee;
}
String displayAmount = Helper.getDisplayAmount(realAmount, Helper.DISPLAY_DIGITS_INFO);
String displayAmount = Helper.getDisplayAmount(infoItem.amount, Helper.DISPLAY_DIGITS_INFO);
if (infoItem.direction == TransactionInfo.Direction.Direction_Out) {
tvAmount.setText(context.getString(R.string.tx_list_amount_negative, displayAmount));
} else {

View File

@@ -0,0 +1,45 @@
/*
* Copyright (c) 2018 m2049r
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.m2049r.xmrwallet.model;
public enum NetworkType {
NetworkType_Mainnet(0),
NetworkType_Testnet(1),
NetworkType_Stagenet(2);
public static NetworkType fromInteger(int n) {
switch (n) {
case 0:
return NetworkType_Mainnet;
case 1:
return NetworkType_Testnet;
case 2:
return NetworkType_Stagenet;
}
return null;
}
public int getValue() {
return value;
}
private int value;
NetworkType(int value) {
this.value = value;
}
}

View File

@@ -84,7 +84,14 @@ public class PendingTransaction {
public native long getFee();
public native String getFirstTxId();
public String getFirstTxId() {
String id = getFirstTxIdJ();
if (id == null)
throw new IndexOutOfBoundsException();
return id;
}
public native String getFirstTxIdJ();
public native long getTxCount();

View File

@@ -79,7 +79,11 @@ public class Wallet {
public native String getPath();
public native boolean isTestNet();
public NetworkType getNetworkType() {
return NetworkType.fromInteger(nettype());
}
public native int nettype();
//TODO virtual void hardForkInfo(uint8_t &version, uint64_t &earliest_height) const = 0;
//TODO virtual bool useForkRules(uint8_t version, int64_t early_blocks) const = 0;
@@ -155,10 +159,10 @@ public class Wallet {
public static native boolean isPaymentIdValid(String payment_id);
public static boolean isAddressValid(String address) {
return isAddressValid(address, WalletManager.getInstance().isTestNet());
return isAddressValid(address, WalletManager.getInstance().getNetworkType().getValue());
}
public static native boolean isAddressValid(String address, boolean isTestNet);
public static native boolean isAddressValid(String address, int networkType);
//TODO static static bool keyValid(const std::string &secret_key_string, const std::string &address_string, bool isViewKey, bool testnet, std::string &error);

View File

@@ -16,6 +16,8 @@
package com.m2049r.xmrwallet.model;
import com.m2049r.xmrwallet.data.WalletNode;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
@@ -69,22 +71,22 @@ public class WalletManager {
}
public Wallet createWallet(File aFile, String password, String language) {
long walletHandle = createWalletJ(aFile.getAbsolutePath(), password, language, isTestNet());
long walletHandle = createWalletJ(aFile.getAbsolutePath(), password, language, getNetworkType().getValue());
Wallet wallet = new Wallet(walletHandle);
manageWallet(wallet);
return wallet;
}
private native long createWalletJ(String path, String password, String language, boolean isTestNet);
private native long createWalletJ(String path, String password, String language, int networkType);
public Wallet openWallet(String path, String password) {
long walletHandle = openWalletJ(path, password, isTestNet());
long walletHandle = openWalletJ(path, password, getNetworkType().getValue());
Wallet wallet = new Wallet(walletHandle);
manageWallet(wallet);
return wallet;
}
private native long openWalletJ(String path, String password, boolean isTestNet);
private native long openWalletJ(String path, String password, int networkType);
public Wallet recoveryWallet(File aFile, String password, String mnemonic) {
return recoveryWallet(aFile, password, mnemonic, 0);
@@ -92,28 +94,28 @@ public class WalletManager {
public Wallet recoveryWallet(File aFile, String password, String mnemonic, long restoreHeight) {
long walletHandle = recoveryWalletJ(aFile.getAbsolutePath(), password, mnemonic,
isTestNet(), restoreHeight);
getNetworkType().getValue(), restoreHeight);
Wallet wallet = new Wallet(walletHandle);
manageWallet(wallet);
return wallet;
}
private native long recoveryWalletJ(String path, String password, String mnemonic,
boolean isTestNet, long restoreHeight);
int networkType, long restoreHeight);
public Wallet createWalletWithKeys(File aFile, String password, String language, long restoreHeight,
String addressString, String viewKeyString, String spendKeyString) {
long walletHandle = createWalletWithKeysJ(aFile.getAbsolutePath(), password,
language, isTestNet(), restoreHeight,
long walletHandle = createWalletFromKeysJ(aFile.getAbsolutePath(), password,
language, getNetworkType().getValue(), restoreHeight,
addressString, viewKeyString, spendKeyString);
Wallet wallet = new Wallet(walletHandle);
manageWallet(wallet);
return wallet;
}
private native long createWalletWithKeysJ(String path, String password,
private native long createWalletFromKeysJ(String path, String password,
String language,
boolean isTestNet,
int networkType,
long restoreHeight,
String addressString,
String viewKeyString,
@@ -204,24 +206,23 @@ public class WalletManager {
//TODO virtual bool checkPayment(const std::string &address, const std::string &txid, const std::string &txkey, const std::string &daemon_address, uint64_t &received, uint64_t &height, std::string &error) const = 0;
private String daemonAddress = null;
private boolean testnet = true;
private NetworkType networkType = null;
public boolean isTestNet() {
if (daemonAddress == null) {
return true;
// assume testnet not explicitly initialised
//throw new IllegalStateException("use setDaemon() to initialise daemon and net first!");
}
return testnet;
public NetworkType getNetworkType() {
return networkType;
}
public void setDaemon(String address, boolean testnet, String username, String password) {
//Timber.d("SETDAEMON " + username + "/" + password + "/" + address);
this.daemonAddress = address;
this.testnet = testnet;
this.daemonUsername = username;
this.daemonPassword = password;
setDaemonAddressJ(address);
//public void setDaemon(String address, NetworkType networkType, String username, String password) {
public void setDaemon(WalletNode walletNode) {
this.daemonAddress = walletNode.getAddress();
this.networkType = networkType;
this.daemonUsername = walletNode.getUsername();
this.daemonPassword = walletNode.getPassword();
setDaemonAddressJ(daemonAddress);
}
public void setNetworkType(NetworkType networkType) {
this.networkType = networkType;
}
public String getDaemonAddress() {

View File

@@ -524,7 +524,7 @@ public class WalletService extends Service {
showProgress(20);
Wallet wallet = null;
WalletManager walletMgr = WalletManager.getInstance();
Timber.d("WalletManager testnet=%s", walletMgr.isTestNet());
Timber.d("WalletManager network=%s", walletMgr.getNetworkType().name());
showProgress(30);
if (walletMgr.walletExists(path)) {
Timber.d("open wallet %s", path);

View File

@@ -18,6 +18,9 @@ package com.m2049r.xmrwallet.util;
// based on https://rosettacode.org/wiki/Bitcoin/address_validation#Java
import com.m2049r.xmrwallet.model.NetworkType;
import com.m2049r.xmrwallet.model.WalletManager;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
@@ -27,6 +30,11 @@ public class BitcoinAddressValidator {
private static final String ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
public static boolean validate(String addrress) {
return validate(addrress,
WalletManager.getInstance().getNetworkType() != NetworkType.NetworkType_Mainnet);
}
public static boolean validate(String addrress, boolean testnet) {
if (addrress.length() < 26 || addrress.length() > 35)
return false;

View File

@@ -31,12 +31,15 @@ import android.graphics.drawable.Drawable;
import android.graphics.drawable.VectorDrawable;
import android.os.Environment;
import android.support.v4.content.ContextCompat;
import android.system.ErrnoException;
import android.system.Os;
import android.view.WindowManager;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.view.inputmethod.InputMethodManager;
import com.m2049r.xmrwallet.R;
import com.m2049r.xmrwallet.model.NetworkType;
import com.m2049r.xmrwallet.model.Wallet;
import com.m2049r.xmrwallet.model.WalletManager;
@@ -55,16 +58,21 @@ import timber.log.Timber;
public class Helper {
static private final String WALLET_DIR = "monerujo";
static private final String HOME_DIR = "monero";
static public int DISPLAY_DIGITS_INFO = 5;
static public File getStorageRoot(Context context) {
static public File getWalletRoot(Context context) {
return getStorage(context, WALLET_DIR);
}
static public File getStorage(Context context, String folderName) {
if (!isExternalStorageWritable()) {
String msg = context.getString(R.string.message_strorage_not_writable);
Timber.e(msg);
throw new IllegalStateException(msg);
}
File dir = new File(Environment.getExternalStorageDirectory(), WALLET_DIR);
File dir = new File(Environment.getExternalStorageDirectory(), folderName);
if (!dir.exists()) {
Timber.i("Creating %s", dir.getAbsolutePath());
dir.mkdirs(); // try to make it
@@ -114,9 +122,9 @@ public class Helper {
}
static public File getWalletFile(Context context, String aWalletName) {
File walletDir = getStorageRoot(context);
File walletDir = getWalletRoot(context);
File f = new File(walletDir, aWalletName);
Timber.d("wallet= %s size= %d", f.getAbsolutePath(), f.length());
Timber.d("wallet=%s size= %d", f.getAbsolutePath(), f.length());
return f;
}
@@ -263,10 +271,20 @@ public class Helper {
}
static public HttpUrl getXmrToBaseUrl() {
if ((WalletManager.getInstance() == null) || WalletManager.getInstance().isTestNet()) {
if ((WalletManager.getInstance() == null)
|| (WalletManager.getInstance().getNetworkType() != NetworkType.NetworkType_Mainnet)) {
return HttpUrl.parse("https://test.xmr.to/api/v2/xmr2btc/");
} else {
return HttpUrl.parse("https://xmr.to/api/v2/xmr2btc/");
}
}
static public void setMoneroHome(Context context) {
try {
String home = getStorage(context, HOME_DIR).getAbsolutePath();
Os.setenv("HOME", home, true);
} catch (ErrnoException ex) {
throw new IllegalStateException(ex);
}
}
}

View File

@@ -45,7 +45,7 @@ public class Toolbar extends android.support.v7.widget.Toolbar {
ImageView toolbarImage;
TextView toolbarTitle;
TextView toolbarSubtitle;
Button bDonate;
Button bCredits;
public Toolbar(Context context) {
super(context);
@@ -87,8 +87,8 @@ public class Toolbar extends android.support.v7.widget.Toolbar {
toolbarTitle = (TextView) findViewById(R.id.toolbarTitle);
toolbarSubtitle = (TextView) findViewById(R.id.toolbarSubtitle);
bDonate = (Button) findViewById(R.id.bDonate);
bDonate.setOnClickListener(new View.OnClickListener() {
bCredits = (Button) findViewById(R.id.bCredits);
bCredits.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
if (onButtonListener != null) {
onButtonListener.onButton(buttonType);
@@ -116,43 +116,43 @@ public class Toolbar extends android.support.v7.widget.Toolbar {
public final static int BUTTON_NONE = 0;
public final static int BUTTON_BACK = 1;
public final static int BUTTON_CLOSE = 2;
public final static int BUTTON_DONATE = 3;
public final static int BUTTON_CREDITS = 3;
public final static int BUTTON_CANCEL = 4;
int buttonType = BUTTON_DONATE;
int buttonType = BUTTON_CREDITS;
public void setButton(int type) {
switch (type) {
case BUTTON_BACK:
Timber.d("BUTTON_BACK");
bDonate.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_arrow_back_white_24dp, 0, 0, 0);
bDonate.setText(null);
bDonate.setVisibility(View.VISIBLE);
bCredits.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_arrow_back_white_24dp, 0, 0, 0);
bCredits.setText(null);
bCredits.setVisibility(View.VISIBLE);
break;
case BUTTON_CLOSE:
Timber.d("BUTTON_CLOSE");
bDonate.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_close_white_24dp, 0, 0, 0);
bDonate.setText(R.string.label_close);
bDonate.setVisibility(View.VISIBLE);
bCredits.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_close_white_24dp, 0, 0, 0);
bCredits.setText(R.string.label_close);
bCredits.setVisibility(View.VISIBLE);
break;
case BUTTON_DONATE:
Timber.d("BUTTON_DONATE");
bDonate.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_favorite_white_24dp, 0, 0, 0);
bDonate.setText(R.string.label_donate);
bDonate.setVisibility(View.VISIBLE);
case BUTTON_CREDITS:
Timber.d("BUTTON_CREDITS");
bCredits.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_favorite_white_24dp, 0, 0, 0);
bCredits.setText(R.string.label_credits);
bCredits.setVisibility(View.VISIBLE);
break;
case BUTTON_CANCEL:
Timber.d("BUTTON_CANCEL");
bDonate.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_close_white_24dp, 0, 0, 0);
bDonate.setText(R.string.label_cancel);
bDonate.setVisibility(View.VISIBLE);
bCredits.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_close_white_24dp, 0, 0, 0);
bCredits.setText(R.string.label_cancel);
bCredits.setVisibility(View.VISIBLE);
break;
case BUTTON_NONE:
default:
Timber.d("BUTTON_NONE");
bDonate.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0);
bDonate.setText(null);
bDonate.setVisibility(View.INVISIBLE);
bCredits.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0);
bCredits.setText(null);
bCredits.setVisibility(View.INVISIBLE);
}
buttonType = type;
}

View File

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

View File

@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="8dp"
android:paddingEnd="16dp"
android:paddingStart="16dp">
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<ImageView
android:layout_width="match_parent"
android:layout_height="100dp"
android:src="@drawable/gunther_coder" />
<TextView
android:id="@+id/tvCredits"
style="@style/MoneroText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/header_top"
android:autoLink="web"
android:gravity="center"
android:text="@string/credits_text" />
</LinearLayout>
</ScrollView>

View File

@@ -1,79 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="8dp"
android:paddingEnd="16dp"
android:paddingStart="16dp">
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<ImageView
android:layout_width="match_parent"
android:layout_height="100dp"
android:src="@drawable/gunther_donate" />
<TextView
style="@style/MoneroText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="@string/donation_text"
android:textSize="14sp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/header_top"
android:background="@drawable/backgound_spinner"
android:orientation="vertical"
android:padding="@dimen/header_top">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
style="@style/MoneroLabel.Heading.Donation"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="center"
android:text="@string/donation_address_label" />
<ImageButton
android:id="@+id/bCopyAddress"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end"
android:layout_marginEnd="8dp"
android:background="?android:selectableItemBackground"
android:src="@drawable/ic_content_copy_black_24dp" />
</FrameLayout>
<TextView
android:id="@+id/tvWalletAddress"
style="@style/MoneroText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/data_top"
android:text="@string/donation_address"
android:textAlignment="center"
android:textColor="@color/moneroBlack"
android:textSize="17sp" />
</LinearLayout>
<TextView
android:id="@+id/tvCredits"
style="@style/MoneroText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/header_top"
android:autoLink="web"
android:gravity="center"
android:text="@string/donation_credits" />
</LinearLayout>
</ScrollView>

View File

@@ -3,12 +3,12 @@
xmlns:tools="http://schemas.android.com/tools">
<Button
android:id="@+id/bDonate"
android:id="@+id/bCredits"
style="@style/ToolBarStyle.ActionButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:drawableStart="@drawable/ic_favorite_white_24dp"
android:text="@string/label_donate" />
android:text="@string/label_credits" />
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"

View File

@@ -3,10 +3,10 @@
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/action_donate"
android:id="@+id/action_credits"
android:icon="@drawable/ic_favorite_white_24dp"
android:orderInCategory="10"
android:title="@string/label_donate"
android:title="@string/label_credits"
app:showAsAction="ifRoom" />
<item

View File

@@ -4,13 +4,7 @@
<string name="about_close">Cerrar</string>
<string name="about_version">Versión %1$s (%2$d)</string>
<string name="donation_text">
\"¡Donad, bastardos ingratos!\"
</string>
<string name="donation_address_label">Donaciones</string>
<string name="donation_credits"><![CDATA[
<string name="credits_text"><![CDATA[
<b>Créditos</b>
<br/>
m2049r, baltsar777, anhdres, keejef,

View File

@@ -20,7 +20,7 @@
<string name="password_very_strong">¡Bien ahí, hacker nivel 4!</string>
<string name="label_login_wallets">Monederos</string>
<string name="label_donate">Donar</string>
<string name="label_credits">Créditos</string>
<string name="label_ok">Aceptar</string>
<string name="label_cancel">Cancelar</string>
<string name="label_close">Cerrar</string>
@@ -59,6 +59,7 @@
<string name="label_daemon">Nodo</string>
<string name="prompt_daemon">([&lt;usuario&gt;:&lt;contraseña&gt;@]&lt;daemon&gt;[:&lt;puerto&gt;])</string>
<string name="prompt_mainnet">Selección de Red</string>
<string name="connect_stagenet">StageNet</string>
<string name="connect_testnet">TestNet</string>
<string name="connect_mainnet">MainNet</string>
<string name="status_walletlist_loading">Cargando lista de monederos</string>

View File

@@ -5,14 +5,7 @@
<string name="about_whoami">I am monerujo</string>
<string name="about_version">Version %1$s (%2$d)</string>
<string name="donation_text">
\"Donate you ungrateful bastards!\"
</string>
<string name="donation_address_label">Donations Address</string>
<string name="donation_address" translatable="false">4AdkPJoxn7JCvAby9szgnt93MSEwdnxdhaASxbTBm6x5dCwmsDep2UYN4FhStDn5i11nsJbpU7oj59ahg8gXb1Mg3viqCuk</string>
<string name="donation_credits"><![CDATA[
<string name="credits_text"><![CDATA[
<b>Credits</b>
<br/>
m2049r, baltsar777, anhdres, keejef,
@@ -292,6 +285,8 @@
Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
<h3>easylogging++ (https://github.com/monero-project/monero/tree/master/external/easylogging%2B%2B)</h3>
Copyright (c) 2017 muflihun.com
<h3>zxcvbn4j (https://github.com/nulab/zxcvbn4j)</h3>
Copyright (c) 2014 Nulab Inc
<h3>The MIT License</h3>
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:<br/>
<br/>

Some files were not shown because too many files have changed in this diff Show More