mirror of
https://github.com/m2049r/xmrwallet
synced 2025-09-10 05:40:51 +02:00
Compare commits
28 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
110057c294 | ||
![]() |
7553d3c5f4 | ||
![]() |
317976b34a | ||
![]() |
6ad423567f | ||
![]() |
d497158856 | ||
![]() |
f4cada5fa1 | ||
![]() |
352f0ad09c | ||
![]() |
ff1a9c1570 | ||
![]() |
fa811a39a2 | ||
![]() |
cf5018be33 | ||
![]() |
8ec027f9d4 | ||
![]() |
f28428e677 | ||
![]() |
294084bec5 | ||
![]() |
4349907627 | ||
![]() |
f7cef24a83 | ||
![]() |
2774f99b15 | ||
![]() |
bc630fc445 | ||
![]() |
895cf16d33 | ||
![]() |
7f1796b12e | ||
![]() |
abe5c8afab | ||
![]() |
47f79b5269 | ||
![]() |
c9c07eaa15 | ||
![]() |
a490e3af0c | ||
![]() |
64d5b3bdea | ||
![]() |
bf91eaf22f | ||
![]() |
2c3e73b540 | ||
![]() |
830d9dadb9 | ||
![]() |
331d88ebba |
@@ -137,7 +137,11 @@ set_target_properties(checkpoints PROPERTIES IMPORTED_LOCATION
|
||||
|
||||
add_library(device STATIC IMPORTED)
|
||||
set_target_properties(device PROPERTIES IMPORTED_LOCATION
|
||||
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libdevice.a)
|
||||
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libdevice.a)
|
||||
|
||||
add_library(device_trezor STATIC IMPORTED)
|
||||
set_target_properties(device_trezor PROPERTIES IMPORTED_LOCATION
|
||||
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libdevice_trezor.a)
|
||||
|
||||
add_library(multisig STATIC IMPORTED)
|
||||
set_target_properties(multisig PROPERTIES IMPORTED_LOCATION
|
||||
@@ -147,6 +151,10 @@ add_library(version STATIC IMPORTED)
|
||||
set_target_properties(version PROPERTIES IMPORTED_LOCATION
|
||||
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libversion.a)
|
||||
|
||||
add_library(net STATIC IMPORTED)
|
||||
set_target_properties(net PROPERTIES IMPORTED_LOCATION
|
||||
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libnet.a)
|
||||
|
||||
#############
|
||||
# System
|
||||
#############
|
||||
@@ -166,6 +174,7 @@ target_link_libraries( monerujo
|
||||
mnemonics
|
||||
ringct
|
||||
ringct_basic
|
||||
net
|
||||
common
|
||||
cncrypto
|
||||
blockchain_db
|
||||
@@ -176,6 +185,7 @@ target_link_libraries( monerujo
|
||||
blocks
|
||||
checkpoints
|
||||
device
|
||||
device_trezor
|
||||
multisig
|
||||
version
|
||||
|
||||
|
@@ -7,8 +7,8 @@ android {
|
||||
applicationId "com.m2049r.xmrwallet"
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 28
|
||||
versionCode 176
|
||||
versionName "1.11.6 'Chernushka'"
|
||||
versionCode 183
|
||||
versionName "1.11.13 'Chernushka'"
|
||||
|
||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||
externalNativeBuild {
|
||||
|
@@ -1,88 +0,0 @@
|
||||
// Copyright (c) 2017-2018, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
#if defined(HAVE_MONERUJO)
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief LedgerFind - find Ledger Device and return it's name
|
||||
* @param buffer - buffer for name of found device
|
||||
* @param len - length of buffer
|
||||
* @return 0 - success
|
||||
* -1 - no device connected / found
|
||||
* -2 - JVM not found
|
||||
*/
|
||||
int LedgerFind(char *buffer, size_t len);
|
||||
|
||||
/**
|
||||
* @brief LedgerExchange - exchange data with Ledger Device
|
||||
* @param command - buffer for data to send
|
||||
* @param cmd_len - length of send to send
|
||||
* @param response - buffer for received data
|
||||
* @param max_resp_len - size of receive buffer
|
||||
*
|
||||
* @return length of received data in response or -1 if error
|
||||
*/
|
||||
int LedgerExchange(unsigned char *command, unsigned int cmd_len, unsigned char *response, unsigned int max_resp_len);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#include "device_io.hpp"
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace hw {
|
||||
namespace io {
|
||||
class device_io_monerujo: device_io {
|
||||
public:
|
||||
device_io_monerujo() {};
|
||||
~device_io_monerujo() {};
|
||||
|
||||
void init() {};
|
||||
void release() {};
|
||||
|
||||
void connect(void *params) {};
|
||||
void disconnect() {};
|
||||
bool connected() const {return true;}; // monerujo is always connected before it gets here
|
||||
|
||||
// returns number of bytes read or -1 on error
|
||||
int exchange(unsigned char *command, unsigned int cmd_len, unsigned char *response, unsigned int max_resp_len) {
|
||||
return LedgerExchange(command, cmd_len, response, max_resp_len);
|
||||
}
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
#endif //#if defined(HAVE_MONERUJO)
|
@@ -39,6 +39,7 @@ static jclass class_WalletListener;
|
||||
static jclass class_TransactionInfo;
|
||||
static jclass class_Transfer;
|
||||
static jclass class_Ledger;
|
||||
static jclass class_WalletStatus;
|
||||
|
||||
std::mutex _listenerMutex;
|
||||
|
||||
@@ -61,6 +62,8 @@ JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) {
|
||||
jenv->FindClass("com/m2049r/xmrwallet/model/WalletListener")));
|
||||
class_Ledger = static_cast<jclass>(jenv->NewGlobalRef(
|
||||
jenv->FindClass("com/m2049r/xmrwallet/ledger/Ledger")));
|
||||
class_WalletStatus = static_cast<jclass>(jenv->NewGlobalRef(
|
||||
jenv->FindClass("com/m2049r/xmrwallet/model/Wallet$Status")));
|
||||
return JNI_VERSION_1_6;
|
||||
}
|
||||
#ifdef __cplusplus
|
||||
@@ -581,10 +584,25 @@ Java_com_m2049r_xmrwallet_model_Wallet_getStatusJ(JNIEnv *env, jobject instance)
|
||||
return wallet->status();
|
||||
}
|
||||
|
||||
JNIEXPORT jstring JNICALL
|
||||
Java_com_m2049r_xmrwallet_model_Wallet_getErrorString(JNIEnv *env, jobject instance) {
|
||||
jobject newWalletStatusInstance(JNIEnv *env, int status, const std::string &errorString) {
|
||||
jmethodID init = env->GetMethodID(class_WalletStatus, "<init>",
|
||||
"(ILjava/lang/String;)V");
|
||||
jstring _errorString = env->NewStringUTF(errorString.c_str());
|
||||
jobject instance = env->NewObject(class_WalletStatus, init, status, _errorString);
|
||||
env->DeleteLocalRef(_errorString);
|
||||
return instance;
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT jobject JNICALL
|
||||
Java_com_m2049r_xmrwallet_model_Wallet_statusWithErrorString(JNIEnv *env, jobject instance) {
|
||||
Bitmonero::Wallet *wallet = getHandle<Bitmonero::Wallet>(env, instance);
|
||||
return env->NewStringUTF(wallet->errorString().c_str());
|
||||
|
||||
int status;
|
||||
std::string errorString;
|
||||
wallet->statusWithErrorString(status, errorString);
|
||||
|
||||
return newWalletStatusInstance(env, status, errorString);
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL
|
||||
@@ -1292,7 +1310,6 @@ Java_com_m2049r_xmrwallet_model_PendingTransaction_getFirstTxIdJ(JNIEnv *env, jo
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT jlong JNICALL
|
||||
Java_com_m2049r_xmrwallet_model_PendingTransaction_getTxCount(JNIEnv *env, jobject instance) {
|
||||
Bitmonero::PendingTransaction *tx = getHandle<Bitmonero::PendingTransaction>(env, instance);
|
||||
@@ -1378,12 +1395,15 @@ Java_com_m2049r_xmrwallet_model_WalletManager_setLogLevel(JNIEnv *env, jclass cl
|
||||
Bitmonero::WalletManagerFactory::setLogLevel(level);
|
||||
}
|
||||
|
||||
JNIEXPORT jstring JNICALL
|
||||
Java_com_m2049r_xmrwallet_model_WalletManager_moneroVersion(JNIEnv *env, jclass clazz) {
|
||||
return env->NewStringUTF(MONERO_VERSION);
|
||||
}
|
||||
|
||||
//
|
||||
// Ledger Stuff
|
||||
//
|
||||
|
||||
#include "device_io_monerujo.hpp"
|
||||
|
||||
/**
|
||||
* @brief LedgerExchange - exchange data with Ledger Device
|
||||
* @param command - buffer for data to send
|
||||
@@ -1417,7 +1437,7 @@ int LedgerExchange(
|
||||
return -1;
|
||||
}
|
||||
jsize len = jenv->GetArrayLength(dataRecv);
|
||||
LOGD("LedgerExchange SCARD_S_SUCCESS %ld/%d", cmd_len, len);
|
||||
LOGD("LedgerExchange SCARD_S_SUCCESS %u/%d", cmd_len, len);
|
||||
if (len <= max_resp_len) {
|
||||
jenv->GetByteArrayRegion(dataRecv, 0, len, (jbyte *) response);
|
||||
jenv->DeleteLocalRef(dataRecv);
|
||||
|
@@ -54,6 +54,8 @@ extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
extern const char* const MONERO_VERSION; // the actual monero core version
|
||||
|
||||
// from monero-core crypto/hash-ops.h - avoid #including monero code here
|
||||
enum {
|
||||
HASH_SIZE = 32,
|
||||
|
@@ -46,8 +46,12 @@ public class BTChipTransportAndroidHID implements BTChipTransport {
|
||||
HashMap<String, UsbDevice> deviceList = manager.getDeviceList();
|
||||
for (UsbDevice device : deviceList.values()) {
|
||||
Timber.d("%04X:%04X %s, %s", device.getVendorId(), device.getProductId(), device.getManufacturerName(), device.getProductName());
|
||||
if ((device.getVendorId() == VID) && (device.getProductId() == PID_HID)) {
|
||||
return device;
|
||||
if (device.getVendorId() == VID) {
|
||||
final int deviceProductId = device.getProductId();
|
||||
for (int pid : PID_HIDS) {
|
||||
if (deviceProductId == pid)
|
||||
return device;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
@@ -74,7 +78,7 @@ public class BTChipTransportAndroidHID implements BTChipTransport {
|
||||
}
|
||||
|
||||
private static final int VID = 0x2C97;
|
||||
private static final int PID_HID = 0x0001;
|
||||
private static final int[] PID_HIDS = {0x0001, 0x0004};
|
||||
|
||||
private UsbDeviceConnection connection;
|
||||
private UsbInterface dongleInterface;
|
||||
|
@@ -682,8 +682,7 @@ public class GenerateFragment extends Fragment {
|
||||
}
|
||||
});
|
||||
|
||||
// set FLAG_SECURE to prevent screenshots in Release Mode
|
||||
if (!(BuildConfig.DEBUG && BuildConfig.FLAVOR_type.equals("alpha"))) {
|
||||
if (Helper.preventScreenshot()) {
|
||||
ledgerDialog.getWindow().setFlags(WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE);
|
||||
}
|
||||
|
||||
|
@@ -55,6 +55,8 @@ import com.m2049r.xmrwallet.util.KeyStoreHelper;
|
||||
import com.m2049r.xmrwallet.util.MoneroThreadPoolExecutor;
|
||||
import com.m2049r.xmrwallet.widget.Toolbar;
|
||||
|
||||
import java.text.NumberFormat;
|
||||
|
||||
import timber.log.Timber;
|
||||
|
||||
public class GenerateReviewFragment extends Fragment {
|
||||
@@ -72,6 +74,7 @@ public class GenerateReviewFragment extends Fragment {
|
||||
private TextView tvWalletPassword;
|
||||
private TextView tvWalletAddress;
|
||||
private TextView tvWalletMnemonic;
|
||||
private TextView tvWalletHeight;
|
||||
private TextView tvWalletViewKey;
|
||||
private TextView tvWalletSpendKey;
|
||||
private ImageButton bCopyAddress;
|
||||
@@ -99,6 +102,7 @@ public class GenerateReviewFragment extends Fragment {
|
||||
tvWalletViewKey = view.findViewById(R.id.tvWalletViewKey);
|
||||
tvWalletSpendKey = view.findViewById(R.id.tvWalletSpendKey);
|
||||
tvWalletMnemonic = view.findViewById(R.id.tvWalletMnemonic);
|
||||
tvWalletHeight = view.findViewById(R.id.tvWalletHeight);
|
||||
bCopyAddress = view.findViewById(R.id.bCopyAddress);
|
||||
bAdvancedInfo = view.findViewById(R.id.bAdvancedInfo);
|
||||
llAdvancedInfo = view.findViewById(R.id.llAdvancedInfo);
|
||||
@@ -188,11 +192,12 @@ public class GenerateReviewFragment extends Fragment {
|
||||
private class AsyncShow extends AsyncTask<String, Void, Boolean> {
|
||||
String name;
|
||||
String address;
|
||||
long height;
|
||||
String seed;
|
||||
String viewKey;
|
||||
String spendKey;
|
||||
boolean isWatchOnly;
|
||||
Wallet.Status status;
|
||||
Wallet.Status walletStatus;
|
||||
|
||||
boolean dialogOpened = false;
|
||||
|
||||
@@ -224,14 +229,15 @@ public class GenerateReviewFragment extends Fragment {
|
||||
closeWallet = true;
|
||||
}
|
||||
name = wallet.getName();
|
||||
status = wallet.getStatus();
|
||||
if (status != Wallet.Status.Status_Ok) {
|
||||
Timber.e(wallet.getErrorString());
|
||||
walletStatus = wallet.getStatus();
|
||||
if (!walletStatus.isOk()) {
|
||||
Timber.e(walletStatus.getErrorString());
|
||||
if (closeWallet) wallet.close();
|
||||
return false;
|
||||
}
|
||||
|
||||
address = wallet.getAddress();
|
||||
height = wallet.getRestoreHeight();
|
||||
seed = wallet.getSeed();
|
||||
switch (wallet.getDeviceType()) {
|
||||
case Device_Ledger:
|
||||
@@ -264,6 +270,7 @@ public class GenerateReviewFragment extends Fragment {
|
||||
llPassword.setVisibility(View.VISIBLE);
|
||||
tvWalletPassword.setText(getPassword());
|
||||
tvWalletAddress.setText(address);
|
||||
tvWalletHeight.setText(NumberFormat.getInstance().format(height));
|
||||
if (!seed.isEmpty()) {
|
||||
llMnemonic.setVisibility(View.VISIBLE);
|
||||
tvWalletMnemonic.setText(seed);
|
||||
@@ -287,10 +294,11 @@ public class GenerateReviewFragment extends Fragment {
|
||||
GenerateReviewFragment.VIEW_TYPE_ACCEPT.equals(type) ? Toolbar.BUTTON_NONE : Toolbar.BUTTON_BACK);
|
||||
} else {
|
||||
// TODO show proper error message and/or end the fragment?
|
||||
tvWalletAddress.setText(status.toString());
|
||||
tvWalletMnemonic.setText(status.toString());
|
||||
tvWalletViewKey.setText(status.toString());
|
||||
tvWalletSpendKey.setText(status.toString());
|
||||
tvWalletAddress.setText(walletStatus.toString());
|
||||
tvWalletHeight.setText(walletStatus.toString());
|
||||
tvWalletMnemonic.setText(walletStatus.toString());
|
||||
tvWalletViewKey.setText(walletStatus.toString());
|
||||
tvWalletSpendKey.setText(walletStatus.toString());
|
||||
}
|
||||
hideProgress();
|
||||
}
|
||||
@@ -414,12 +422,13 @@ public class GenerateReviewFragment extends Fragment {
|
||||
}
|
||||
|
||||
boolean ok = false;
|
||||
if (wallet.getStatus() == Wallet.Status.Status_Ok) {
|
||||
Wallet.Status walletStatus = wallet.getStatus();
|
||||
if (walletStatus.isOk()) {
|
||||
wallet.setPassword(newPassword);
|
||||
wallet.store();
|
||||
ok = true;
|
||||
} else {
|
||||
Timber.e(wallet.getErrorString());
|
||||
Timber.e(walletStatus.getErrorString());
|
||||
}
|
||||
if (closeWallet) wallet.close();
|
||||
return ok;
|
||||
@@ -621,8 +630,8 @@ public class GenerateReviewFragment extends Fragment {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
// set FLAG_SECURE to prevent screenshots in Release Mode
|
||||
if (!(BuildConfig.DEBUG && BuildConfig.FLAVOR_type.equals("alpha"))) {
|
||||
|
||||
if (Helper.preventScreenshot()) {
|
||||
openDialog.getWindow().setFlags(WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE);
|
||||
}
|
||||
|
||||
|
@@ -918,6 +918,16 @@ public class LoginActivity extends BaseActivity
|
||||
|
||||
}
|
||||
|
||||
boolean checkAndCloseWallet(Wallet aWallet) {
|
||||
Wallet.Status walletStatus = aWallet.getStatus();
|
||||
if (!walletStatus.isOk()) {
|
||||
Timber.e(walletStatus.getErrorString());
|
||||
toast(walletStatus.getErrorString());
|
||||
}
|
||||
aWallet.close();
|
||||
return walletStatus.isOk();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGenerate(final String name, final String password) {
|
||||
createWallet(name, password,
|
||||
@@ -929,15 +939,13 @@ public class LoginActivity extends BaseActivity
|
||||
|
||||
@Override
|
||||
public boolean createWallet(File aFile, String password) {
|
||||
NodeInfo currentNode = getNode();
|
||||
// get it from the connected node if we have one, and go back ca. 4 days
|
||||
final long restoreHeight =
|
||||
(currentNode != null) ? currentNode.getHeight() - 2000 : -1;
|
||||
Wallet newWallet = WalletManager.getInstance()
|
||||
.createWallet(aFile, password, MNEMONIC_LANGUAGE);
|
||||
boolean success = (newWallet.getStatus() == Wallet.Status.Status_Ok);
|
||||
if (!success) {
|
||||
Timber.e(newWallet.getErrorString());
|
||||
toast(newWallet.getErrorString());
|
||||
}
|
||||
newWallet.close();
|
||||
return success;
|
||||
.createWallet(aFile, password, MNEMONIC_LANGUAGE, restoreHeight);
|
||||
return checkAndCloseWallet(newWallet);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -956,13 +964,7 @@ public class LoginActivity extends BaseActivity
|
||||
public boolean createWallet(File aFile, String password) {
|
||||
Wallet newWallet = WalletManager.getInstance()
|
||||
.recoveryWallet(aFile, password, seed, restoreHeight);
|
||||
boolean success = (newWallet.getStatus() == Wallet.Status.Status_Ok);
|
||||
if (!success) {
|
||||
Timber.e(newWallet.getErrorString());
|
||||
toast(newWallet.getErrorString());
|
||||
}
|
||||
newWallet.close();
|
||||
return success;
|
||||
return checkAndCloseWallet(newWallet);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -982,13 +984,7 @@ public class LoginActivity extends BaseActivity
|
||||
Wallet newWallet = WalletManager.getInstance()
|
||||
.createWalletFromDevice(aFile, password,
|
||||
restoreHeight, "Ledger");
|
||||
boolean success = (newWallet.getStatus() == Wallet.Status.Status_Ok);
|
||||
if (!success) {
|
||||
Timber.e(newWallet.getErrorString());
|
||||
toast(newWallet.getErrorString());
|
||||
}
|
||||
newWallet.close();
|
||||
return success;
|
||||
return checkAndCloseWallet(newWallet);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -1009,13 +1005,7 @@ public class LoginActivity extends BaseActivity
|
||||
Wallet newWallet = WalletManager.getInstance()
|
||||
.createWalletWithKeys(aFile, password, MNEMONIC_LANGUAGE, restoreHeight,
|
||||
address, viewKey, spendKey);
|
||||
boolean success = (newWallet.getStatus() == Wallet.Status.Status_Ok);
|
||||
if (!success) {
|
||||
Timber.e(newWallet.getErrorString());
|
||||
toast(newWallet.getErrorString());
|
||||
}
|
||||
newWallet.close();
|
||||
return success;
|
||||
return checkAndCloseWallet(newWallet);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -1370,17 +1360,30 @@ public class LoginActivity extends BaseActivity
|
||||
if (Ledger.ENABLED)
|
||||
try {
|
||||
Ledger.connect(usbManager, usbDevice);
|
||||
registerDetachReceiver();
|
||||
onLedgerAction();
|
||||
runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Toast.makeText(LoginActivity.this,
|
||||
getString(R.string.toast_ledger_attached, usbDevice.getProductName()),
|
||||
Toast.LENGTH_SHORT)
|
||||
.show();
|
||||
}
|
||||
});
|
||||
if (!Ledger.check()) {
|
||||
Ledger.disconnect();
|
||||
runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Toast.makeText(LoginActivity.this,
|
||||
getString(R.string.toast_ledger_start_app, usbDevice.getProductName()),
|
||||
Toast.LENGTH_SHORT)
|
||||
.show();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
registerDetachReceiver();
|
||||
onLedgerAction();
|
||||
runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Toast.makeText(LoginActivity.this,
|
||||
getString(R.string.toast_ledger_attached, usbDevice.getProductName()),
|
||||
Toast.LENGTH_SHORT)
|
||||
.show();
|
||||
}
|
||||
});
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
|
@@ -439,10 +439,13 @@ public class LoginFragment extends Fragment implements WalletInfoAdapter.OnInter
|
||||
}
|
||||
Collections.sort(nodesToTest, NodeInfo.BestNodeComparator);
|
||||
NodeInfo bestNode = nodesToTest.get(0);
|
||||
if (bestNode.isValid())
|
||||
return nodesToTest.get(0);
|
||||
else
|
||||
if (bestNode.isValid()) {
|
||||
activityCallback.setNode(bestNode);
|
||||
return bestNode;
|
||||
} else {
|
||||
activityCallback.setNode(null);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -450,7 +453,6 @@ public class LoginFragment extends Fragment implements WalletInfoAdapter.OnInter
|
||||
if (!isAdded()) return;
|
||||
pbNode.setVisibility(View.INVISIBLE);
|
||||
llNode.setVisibility(View.VISIBLE);
|
||||
activityCallback.setNode(result);
|
||||
if (result != null) {
|
||||
Timber.d("found a good node %s", result.toString());
|
||||
showNode(result);
|
||||
|
@@ -506,8 +506,8 @@ public class NodeFragment extends Fragment
|
||||
});
|
||||
}
|
||||
});
|
||||
// set FLAG_SECURE to prevent screenshots in Release Mode
|
||||
if (!(BuildConfig.DEBUG && BuildConfig.FLAVOR_type.equals("alpha"))) {
|
||||
|
||||
if (Helper.preventScreenshot()) {
|
||||
editDialog.getWindow().setFlags(WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE);
|
||||
}
|
||||
|
||||
|
@@ -21,6 +21,7 @@ import android.os.Bundle;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
|
||||
import com.m2049r.xmrwallet.util.Helper;
|
||||
import com.m2049r.xmrwallet.util.LocaleHelper;
|
||||
|
||||
import static android.view.WindowManager.LayoutParams;
|
||||
@@ -30,8 +31,7 @@ public abstract class SecureActivity extends AppCompatActivity {
|
||||
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
// set FLAG_SECURE to prevent screenshots in Release Mode
|
||||
if (!(BuildConfig.DEBUG && BuildConfig.FLAVOR_type.equals("alpha"))) {
|
||||
if (Helper.preventScreenshot()) {
|
||||
getWindow().setFlags(LayoutParams.FLAG_SECURE, LayoutParams.FLAG_SECURE);
|
||||
}
|
||||
}
|
||||
|
@@ -628,23 +628,22 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWalletStarted(final Wallet.ConnectionStatus connStatus) {
|
||||
public void onWalletStarted(final Wallet.Status walletStatus) {
|
||||
runOnUiThread(new Runnable() {
|
||||
public void run() {
|
||||
dismissProgressDialog();
|
||||
switch (connStatus) {
|
||||
case ConnectionStatus_Disconnected:
|
||||
Toast.makeText(WalletActivity.this, getString(R.string.status_wallet_connect_failed), Toast.LENGTH_LONG).show();
|
||||
break;
|
||||
case ConnectionStatus_WrongVersion:
|
||||
if (walletStatus == null) {
|
||||
// guess what went wrong
|
||||
Toast.makeText(WalletActivity.this, getString(R.string.status_wallet_connect_failed), Toast.LENGTH_LONG).show();
|
||||
} else {
|
||||
if (Wallet.ConnectionStatus.ConnectionStatus_WrongVersion == walletStatus.getConnectionStatus())
|
||||
Toast.makeText(WalletActivity.this, getString(R.string.status_wallet_connect_wrongversion), Toast.LENGTH_LONG).show();
|
||||
break;
|
||||
case ConnectionStatus_Connected:
|
||||
break;
|
||||
else if (!walletStatus.isOk())
|
||||
Toast.makeText(WalletActivity.this, walletStatus.getErrorString(), Toast.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
});
|
||||
if (connStatus != Wallet.ConnectionStatus.ConnectionStatus_Connected) {
|
||||
if ((walletStatus == null) || (Wallet.ConnectionStatus.ConnectionStatus_Connected != walletStatus.getConnectionStatus())) {
|
||||
finish();
|
||||
} else {
|
||||
haveWallet = true;
|
||||
|
@@ -28,6 +28,7 @@ import android.widget.TextView;
|
||||
|
||||
import com.m2049r.xmrwallet.BuildConfig;
|
||||
import com.m2049r.xmrwallet.R;
|
||||
import com.m2049r.xmrwallet.util.Helper;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
@@ -76,8 +77,7 @@ public class ProgressDialog extends AlertDialog {
|
||||
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
// set FLAG_SECURE to prevent screenshots in Release Mode
|
||||
if (!(BuildConfig.DEBUG && BuildConfig.FLAVOR_type.equals("alpha"))) {
|
||||
if (Helper.preventScreenshot()) {
|
||||
getWindow().setFlags(WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE);
|
||||
}
|
||||
}
|
||||
|
@@ -33,7 +33,9 @@ import android.view.ViewGroup;
|
||||
import android.view.inputmethod.EditorInfo;
|
||||
import android.widget.Button;
|
||||
import android.widget.EditText;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.m2049r.xmrwallet.R;
|
||||
import com.m2049r.xmrwallet.data.BarcodeData;
|
||||
@@ -92,6 +94,7 @@ public class SendAddressWizardFragment extends SendWizardFragment {
|
||||
private View llPaymentId;
|
||||
private TextView tvXmrTo;
|
||||
private View llXmrTo;
|
||||
private ImageButton bPasteAddress;
|
||||
|
||||
private boolean resolvingOA = false;
|
||||
private boolean resolvingPP = false;
|
||||
@@ -197,6 +200,21 @@ public class SendAddressWizardFragment extends SendWizardFragment {
|
||||
}
|
||||
});
|
||||
|
||||
bPasteAddress = view.findViewById(R.id.bPasteAddress);
|
||||
bPasteAddress.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
final String clip = Helper.getClipBoardText(getActivity());
|
||||
if (clip == null) return;
|
||||
// clean it up
|
||||
final String address = clip.replaceAll("[^0-9A-Z-a-z]", "");
|
||||
if (Wallet.isAddressValid(address) || BitcoinAddressValidator.validate(address))
|
||||
etAddress.getEditText().setText(address);
|
||||
else
|
||||
Toast.makeText(getActivity(), getString(R.string.send_address_invalid), Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
});
|
||||
|
||||
etPaymentId = view.findViewById(R.id.etPaymentId);
|
||||
etPaymentId.getEditText().setRawInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
|
||||
etPaymentId.getEditText().setOnEditorActionListener(new TextView.OnEditorActionListener() {
|
||||
|
@@ -437,8 +437,8 @@ public class SendBtcConfirmWizardFragment extends SendWizardFragment implements
|
||||
return false;
|
||||
}
|
||||
});
|
||||
// set FLAG_SECURE to prevent screenshots in Release Mode
|
||||
if (!(BuildConfig.DEBUG && BuildConfig.FLAVOR_type.equals("alpha"))) {
|
||||
|
||||
if (Helper.preventScreenshot()) {
|
||||
passwordDialog.getWindow().setFlags(WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE);
|
||||
}
|
||||
|
||||
|
@@ -324,8 +324,8 @@ public class SendConfirmWizardFragment extends SendWizardFragment implements Sen
|
||||
return false;
|
||||
}
|
||||
});
|
||||
// set FLAG_SECURE to prevent screenshots in Release Mode
|
||||
if (!(BuildConfig.DEBUG && BuildConfig.FLAVOR_type.equals("alpha"))) {
|
||||
|
||||
if (Helper.preventScreenshot()) {
|
||||
passwordDialog.getWindow().setFlags(WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE);
|
||||
}
|
||||
|
||||
|
@@ -134,6 +134,10 @@ public enum Instruction {
|
||||
return value;
|
||||
}
|
||||
|
||||
public byte getByteValue() {
|
||||
return (byte) (value & 0xFF);
|
||||
}
|
||||
|
||||
private int value;
|
||||
|
||||
Instruction(int value) {
|
||||
|
@@ -27,9 +27,11 @@ import com.btchip.BTChipException;
|
||||
import com.btchip.comm.BTChipTransport;
|
||||
import com.btchip.comm.android.BTChipTransportAndroidHID;
|
||||
import com.m2049r.xmrwallet.BuildConfig;
|
||||
import com.m2049r.xmrwallet.model.WalletManager;
|
||||
import com.m2049r.xmrwallet.util.Helper;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import timber.log.Timber;
|
||||
|
||||
@@ -40,9 +42,11 @@ public class Ledger {
|
||||
static public final int LOOKAHEAD_SUBADDRESSES = 20;
|
||||
static public final String SUBADDRESS_LOOKAHEAD = LOOKAHEAD_ACCOUNTS + ":" + LOOKAHEAD_SUBADDRESSES;
|
||||
|
||||
private static final byte PROTOCOL_VERSION = 0x02;
|
||||
public static final int SW_OK = 0x9000;
|
||||
public static final int SW_INS_NOT_SUPPORTED = 0x6D00;
|
||||
public static final int OK[] = {SW_OK};
|
||||
public static final int MINIMUM_LEDGER_VERSION = (1 << 16) + (3 << 8) + (1); // 1.3.1
|
||||
|
||||
public static UsbDevice findDevice(UsbManager usbManager) {
|
||||
if (!ENABLED) return null;
|
||||
@@ -89,6 +93,21 @@ public class Ledger {
|
||||
}
|
||||
}
|
||||
|
||||
static public boolean check() {
|
||||
if (Instance == null) return false;
|
||||
byte[] moneroVersion = WalletManager.moneroVersion().getBytes(StandardCharsets.US_ASCII);
|
||||
|
||||
try {
|
||||
byte[] resp = Instance.exchangeApduNoOpt(Instruction.INS_RESET, moneroVersion, OK);
|
||||
int deviceVersion = (resp[0] << 16) + (resp[1] << 8) + (resp[2]);
|
||||
if (deviceVersion < MINIMUM_LEDGER_VERSION)
|
||||
return false;
|
||||
} catch (BTChipException ex) { // comm error - probably wrong app started on device
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
final private BTChipTransport transport;
|
||||
final private String name;
|
||||
private int lastSW = 0;
|
||||
@@ -112,7 +131,7 @@ public class Ledger {
|
||||
synchronized private byte[] exchangeRaw(byte[] apdu) {
|
||||
if (transport == null)
|
||||
throw new IllegalStateException("No transport (probably closed previously)");
|
||||
Timber.i("exchangeRaw %02x", apdu[1]);
|
||||
Timber.d("exchangeRaw %02x", apdu[1]);
|
||||
Instruction ins = Instruction.fromByte(apdu[1]);
|
||||
if (listener != null) listener.onInstructionSend(ins, apdu);
|
||||
sniffOut(ins, apdu);
|
||||
@@ -120,7 +139,6 @@ public class Ledger {
|
||||
if (listener != null) listener.onInstructionReceive(ins, data);
|
||||
sniffIn(data);
|
||||
return data;
|
||||
|
||||
}
|
||||
|
||||
private byte[] exchange(byte[] apdu) throws BTChipException {
|
||||
@@ -148,68 +166,19 @@ public class Ledger {
|
||||
throw new BTChipException("Invalid status", lastSW);
|
||||
}
|
||||
|
||||
private byte[] exchangeApdu(byte cla, byte ins, byte p1, byte p2, byte[] data, int acceptedSW[]) throws BTChipException {
|
||||
byte[] apdu = new byte[data.length + 5];
|
||||
apdu[0] = cla;
|
||||
apdu[1] = ins;
|
||||
apdu[2] = p1;
|
||||
apdu[3] = p2;
|
||||
apdu[4] = (byte) (data.length);
|
||||
System.arraycopy(data, 0, apdu, 5, data.length);
|
||||
private byte[] exchangeApduNoOpt(Instruction instruction, byte[] data, int acceptedSW[])
|
||||
throws BTChipException {
|
||||
byte[] apdu = new byte[data.length + 6];
|
||||
apdu[0] = PROTOCOL_VERSION;
|
||||
apdu[1] = instruction.getByteValue();
|
||||
apdu[2] = 0; // p1
|
||||
apdu[3] = 0; // p2
|
||||
apdu[4] = (byte) (data.length + 1); // +1 because the opt byte is part of the data
|
||||
apdu[5] = 0; // opt
|
||||
System.arraycopy(data, 0, apdu, 6, data.length);
|
||||
return exchangeCheck(apdu, acceptedSW);
|
||||
}
|
||||
|
||||
private byte[] exchangeApdu(byte cla, byte ins, byte p1, byte p2, int length, int acceptedSW[]) throws BTChipException {
|
||||
byte[] apdu = new byte[5];
|
||||
apdu[0] = cla;
|
||||
apdu[1] = ins;
|
||||
apdu[2] = p1;
|
||||
apdu[3] = p2;
|
||||
apdu[4] = (byte) (length);
|
||||
return exchangeCheck(apdu, acceptedSW);
|
||||
}
|
||||
|
||||
private byte[] exchangeApduSplit(byte cla, byte ins, byte p1, byte p2, byte[] data, int acceptedSW[]) throws BTChipException {
|
||||
int offset = 0;
|
||||
byte[] result = null;
|
||||
while (offset < data.length) {
|
||||
int blockLength = ((data.length - offset) > 255 ? 255 : data.length - offset);
|
||||
byte[] apdu = new byte[blockLength + 5];
|
||||
apdu[0] = cla;
|
||||
apdu[1] = ins;
|
||||
apdu[2] = p1;
|
||||
apdu[3] = p2;
|
||||
apdu[4] = (byte) (blockLength);
|
||||
System.arraycopy(data, offset, apdu, 5, blockLength);
|
||||
result = exchangeCheck(apdu, acceptedSW);
|
||||
offset += blockLength;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private byte[] exchangeApduSplit2(byte cla, byte ins, byte p1, byte p2, byte[] data, byte[] data2, int acceptedSW[]) throws BTChipException {
|
||||
int offset = 0;
|
||||
byte[] result = null;
|
||||
int maxBlockSize = 255 - data2.length;
|
||||
while (offset < data.length) {
|
||||
int blockLength = ((data.length - offset) > maxBlockSize ? maxBlockSize : data.length - offset);
|
||||
boolean lastBlock = ((offset + blockLength) == data.length);
|
||||
byte[] apdu = new byte[blockLength + 5 + (lastBlock ? data2.length : 0)];
|
||||
apdu[0] = cla;
|
||||
apdu[1] = ins;
|
||||
apdu[2] = p1;
|
||||
apdu[3] = p2;
|
||||
apdu[4] = (byte) (blockLength + (lastBlock ? data2.length : 0));
|
||||
System.arraycopy(data, offset, apdu, 5, blockLength);
|
||||
if (lastBlock) {
|
||||
System.arraycopy(data2, 0, apdu, 5 + blockLength, data2.length);
|
||||
}
|
||||
result = exchangeCheck(apdu, acceptedSW);
|
||||
offset += blockLength;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public interface Listener {
|
||||
void onInstructionSend(Instruction ins, byte[] apdu);
|
||||
|
||||
@@ -251,7 +220,6 @@ public class Ledger {
|
||||
if (ins == Instruction.INS_GET_KEY) {
|
||||
snoopKey = (apdu[2] == 2);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void sniffIn(byte[] data) {
|
||||
|
@@ -16,6 +16,9 @@
|
||||
|
||||
package com.m2049r.xmrwallet.model;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
import com.m2049r.xmrwallet.data.TxData;
|
||||
|
||||
import java.io.File;
|
||||
@@ -32,6 +35,47 @@ public class Wallet {
|
||||
System.loadLibrary("monerujo");
|
||||
}
|
||||
|
||||
static public class Status {
|
||||
Status(int status, String errorString) {
|
||||
this.status = StatusEnum.values()[status];
|
||||
this.errorString = errorString;
|
||||
}
|
||||
|
||||
final private StatusEnum status;
|
||||
final private String errorString;
|
||||
@Nullable
|
||||
private ConnectionStatus connectionStatus; // optional
|
||||
|
||||
public StatusEnum getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public String getErrorString() {
|
||||
return errorString;
|
||||
}
|
||||
|
||||
public void setConnectionStatus(@Nullable ConnectionStatus connectionStatus) {
|
||||
this.connectionStatus = connectionStatus;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public ConnectionStatus getConnectionStatus() {
|
||||
return connectionStatus;
|
||||
}
|
||||
|
||||
public boolean isOk() {
|
||||
return (getStatus() == StatusEnum.Status_Ok)
|
||||
&& ((getConnectionStatus() == null) ||
|
||||
(getConnectionStatus() == ConnectionStatus.ConnectionStatus_Connected));
|
||||
}
|
||||
|
||||
@Override
|
||||
@NonNull
|
||||
public String toString() {
|
||||
return "Wallet.Status: (" + status + "/" + errorString + ", " + connectionStatus;
|
||||
}
|
||||
}
|
||||
|
||||
private int accountIndex = 0;
|
||||
|
||||
public int getAccountIndex() {
|
||||
@@ -66,7 +110,7 @@ public class Wallet {
|
||||
Device_Ledger
|
||||
}
|
||||
|
||||
public enum Status {
|
||||
public enum StatusEnum {
|
||||
Status_Ok,
|
||||
Status_Error,
|
||||
Status_Critical
|
||||
@@ -85,12 +129,16 @@ public class Wallet {
|
||||
public native void setSeedLanguage(String language);
|
||||
|
||||
public Status getStatus() {
|
||||
return Wallet.Status.values()[getStatusJ()];
|
||||
return statusWithErrorString();
|
||||
}
|
||||
|
||||
private native int getStatusJ();
|
||||
public Status getFullStatus() {
|
||||
Wallet.Status walletStatus = statusWithErrorString();
|
||||
walletStatus.setConnectionStatus(getConnectionStatus());
|
||||
return walletStatus;
|
||||
}
|
||||
|
||||
public native String getErrorString();
|
||||
private native Status statusWithErrorString();
|
||||
|
||||
public native boolean setPassword(String password);
|
||||
|
||||
|
@@ -91,14 +91,16 @@ public class WalletManager {
|
||||
managedWallet = null;
|
||||
}
|
||||
|
||||
public Wallet createWallet(File aFile, String password, String language) {
|
||||
public Wallet createWallet(File aFile, String password, String language, long height) {
|
||||
long walletHandle = createWalletJ(aFile.getAbsolutePath(), password, language, getNetworkType().getValue());
|
||||
Wallet wallet = new Wallet(walletHandle);
|
||||
manageWallet(wallet);
|
||||
if (wallet.getStatus() == Wallet.Status.Status_Ok) {
|
||||
if (wallet.getStatus().isOk()) {
|
||||
// (Re-)Estimate restore height based on what we know
|
||||
long oldHeight = wallet.getRestoreHeight();
|
||||
wallet.setRestoreHeight(RestoreHeight.getInstance().getHeight(new Date()));
|
||||
final long oldHeight = wallet.getRestoreHeight();
|
||||
final long restoreHeight =
|
||||
(height > -1) ? height : RestoreHeight.getInstance().getHeight(new Date());
|
||||
wallet.setRestoreHeight(restoreHeight);
|
||||
Timber.d("Changed Restore Height from %d to %d", oldHeight, wallet.getRestoreHeight());
|
||||
wallet.setPassword(password); // this rewrites the keys file (which contains the restore height)
|
||||
}
|
||||
@@ -285,7 +287,8 @@ public class WalletManager {
|
||||
this.daemonAddress = null;
|
||||
this.daemonUsername = "";
|
||||
this.daemonPassword = "";
|
||||
setDaemonAddressJ("");
|
||||
//setDaemonAddressJ(""); // don't disconnect as monero code blocks for many seconds!
|
||||
//TODO: need to do something about that later
|
||||
}
|
||||
}
|
||||
|
||||
@@ -351,4 +354,6 @@ public class WalletManager {
|
||||
static public native void logWarning(String category, String message);
|
||||
|
||||
static public native void logError(String category, String message);
|
||||
|
||||
static public native String moneroVersion();
|
||||
}
|
@@ -31,6 +31,7 @@ import android.os.IBinder;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
import android.os.Process;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.annotation.RequiresApi;
|
||||
import android.support.v4.app.NotificationCompat;
|
||||
|
||||
@@ -220,7 +221,7 @@ public class WalletService extends Service {
|
||||
|
||||
void onSendTransactionFailed(String error);
|
||||
|
||||
void onWalletStarted(Wallet.ConnectionStatus walletStatus);
|
||||
void onWalletStarted(Wallet.Status walletStatus);
|
||||
|
||||
void onWalletOpen(Wallet.Device device);
|
||||
}
|
||||
@@ -287,9 +288,9 @@ public class WalletService extends Service {
|
||||
if (walletId != null) {
|
||||
showProgress(getString(R.string.status_wallet_loading));
|
||||
showProgress(10);
|
||||
Wallet.ConnectionStatus connStatus = start(walletId, walletPw);
|
||||
if (observer != null) observer.onWalletStarted(connStatus);
|
||||
if (connStatus != Wallet.ConnectionStatus.ConnectionStatus_Connected) {
|
||||
Wallet.Status walletStatus = start(walletId, walletPw);
|
||||
if (observer != null) observer.onWalletStarted(walletStatus);
|
||||
if ((walletStatus == null) || !walletStatus.isOk()) {
|
||||
errorState = true;
|
||||
stop();
|
||||
}
|
||||
@@ -300,7 +301,7 @@ public class WalletService extends Service {
|
||||
boolean rc = myWallet.store();
|
||||
Timber.d("wallet stored: %s with rc=%b", myWallet.getName(), rc);
|
||||
if (!rc) {
|
||||
Timber.w("Wallet store failed: %s", myWallet.getErrorString());
|
||||
Timber.w("Wallet store failed: %s", myWallet.getStatus().getErrorString());
|
||||
}
|
||||
if (observer != null) observer.onWalletStored(rc);
|
||||
} else if (cmd.equals(REQUEST_CMD_TX)) {
|
||||
@@ -362,7 +363,7 @@ public class WalletService extends Service {
|
||||
boolean rc = myWallet.store();
|
||||
Timber.d("wallet stored: %s with rc=%b", myWallet.getName(), rc);
|
||||
if (!rc) {
|
||||
Timber.w("Wallet store failed: %s", myWallet.getErrorString());
|
||||
Timber.w("Wallet store failed: %s", myWallet.getStatus().getErrorString());
|
||||
}
|
||||
if (observer != null) observer.onWalletStored(rc);
|
||||
listener.updated = true;
|
||||
@@ -464,7 +465,8 @@ public class WalletService extends Service {
|
||||
return true; // true is important so that onUnbind is also called next time
|
||||
}
|
||||
|
||||
private Wallet.ConnectionStatus start(String walletName, String walletPassword) {
|
||||
@Nullable
|
||||
private Wallet.Status start(String walletName, String walletPassword) {
|
||||
Timber.d("start()");
|
||||
startNotfication();
|
||||
showProgress(getString(R.string.status_wallet_loading));
|
||||
@@ -472,11 +474,11 @@ public class WalletService extends Service {
|
||||
if (listener == null) {
|
||||
Timber.d("start() loadWallet");
|
||||
Wallet aWallet = loadWallet(walletName, walletPassword);
|
||||
Wallet.ConnectionStatus connStatus = Wallet.ConnectionStatus.ConnectionStatus_Disconnected;
|
||||
if (aWallet != null) connStatus = aWallet.getConnectionStatus();
|
||||
if (connStatus != Wallet.ConnectionStatus.ConnectionStatus_Connected) {
|
||||
if (aWallet != null) aWallet.close();
|
||||
return connStatus;
|
||||
if (aWallet == null) return null;
|
||||
Wallet.Status walletStatus = aWallet.getFullStatus();
|
||||
if (!walletStatus.isOk()) {
|
||||
aWallet.close();
|
||||
return walletStatus;
|
||||
}
|
||||
listener = new MyWalletListener();
|
||||
listener.start();
|
||||
@@ -487,7 +489,7 @@ public class WalletService extends Service {
|
||||
// if we try to refresh the history here we get occasional segfaults!
|
||||
// doesnt matter since we update as soon as we get a new block anyway
|
||||
Timber.d("start() done");
|
||||
return Wallet.ConnectionStatus.ConnectionStatus_Connected;
|
||||
return getWallet().getFullStatus();
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
@@ -532,10 +534,9 @@ public class WalletService extends Service {
|
||||
wallet = walletMgr.openWallet(path, walletPassword);
|
||||
showProgress(60);
|
||||
Timber.d("wallet opened");
|
||||
Wallet.Status status = wallet.getStatus();
|
||||
Timber.d("wallet status is %s", status);
|
||||
if (status != Wallet.Status.Status_Ok) {
|
||||
Timber.d("wallet status is %s", status);
|
||||
Wallet.Status walletStatus = wallet.getStatus();
|
||||
if (!walletStatus.isOk()) {
|
||||
Timber.d("wallet status is %s", walletStatus);
|
||||
WalletManager.getInstance().close(wallet); // TODO close() failed?
|
||||
wallet = null;
|
||||
// TODO what do we do with the progress??
|
||||
|
@@ -21,6 +21,7 @@ import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.app.Dialog;
|
||||
import android.content.ClipData;
|
||||
import android.content.ClipDescription;
|
||||
import android.content.ClipboardManager;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
@@ -281,6 +282,21 @@ public class Helper {
|
||||
clipboardManager.setPrimaryClip(clip);
|
||||
}
|
||||
|
||||
static public String getClipBoardText(Context context) {
|
||||
final ClipboardManager clipboardManager = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
|
||||
try {
|
||||
if (clipboardManager.hasPrimaryClip()
|
||||
&& clipboardManager.getPrimaryClipDescription().hasMimeType(ClipDescription.MIMETYPE_TEXT_PLAIN)) {
|
||||
final ClipData.Item item = clipboardManager.getPrimaryClip().getItemAt(0);
|
||||
return item.getText().toString();
|
||||
}
|
||||
} catch (NullPointerException ex) {
|
||||
// if we have don't find a text in the clipboard
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
static private Animation ShakeAnimation;
|
||||
|
||||
static public Animation getShakeAnimation(Context context) {
|
||||
@@ -585,8 +601,7 @@ public class Helper {
|
||||
}
|
||||
});
|
||||
|
||||
// set FLAG_SECURE to prevent screenshots in Release Mode
|
||||
if (!(BuildConfig.DEBUG && BuildConfig.FLAVOR_type.equals("alpha"))) {
|
||||
if (Helper.preventScreenshot()) {
|
||||
openDialog.getWindow().setFlags(WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE);
|
||||
}
|
||||
|
||||
@@ -626,4 +641,8 @@ public class Helper {
|
||||
StrictMode.setThreadPolicy(currentPolicy);
|
||||
}
|
||||
}
|
||||
|
||||
static public boolean preventScreenshot() {
|
||||
return !(BuildConfig.DEBUG || BuildConfig.FLAVOR_type.equals("alpha"));
|
||||
}
|
||||
}
|
||||
|
@@ -103,6 +103,8 @@ public class RestoreHeight {
|
||||
blockheight.put("2019-03-01", 1781681L);
|
||||
blockheight.put("2019-04-01", 1803081L);
|
||||
blockheight.put("2019-05-01", 1824671L);
|
||||
blockheight.put("2019-06-01", 1847005L);
|
||||
blockheight.put("2019-07-01", 1868590L);
|
||||
}
|
||||
|
||||
public long getHeight(String date) {
|
||||
|
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="@color/gradientOrange"
|
||||
android:pathData="M19,2h-4.18C14.4,0.84 13.3,0 12,0c-1.3,0 -2.4,0.84 -2.82,2L5,2c-1.1,0 -2,0.9 -2,2v16c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2L21,4c0,-1.1 -0.9,-2 -2,-2zM12,2c0.55,0 1,0.45 1,1s-0.45,1 -1,1 -1,-0.45 -1,-1 0.45,-1 1,-1zM19,20L5,20L5,4h2v3h10L17,4h2v16z" />
|
||||
</vector>
|
@@ -77,6 +77,32 @@
|
||||
tools:text="tucks slackens vehicle doctor oaks aloof balding knife rays wise haggled cuisine navy ladder suitcase dusted last thorn pixels karate ticket nibs violin zapped slackens" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/llHeight"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/data_top"
|
||||
android:orientation="vertical"
|
||||
android:visibility="visible">
|
||||
|
||||
<TextView
|
||||
style="@style/MoneroLabel.Heading"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center"
|
||||
android:text="@string/label_restoreheight" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvWalletHeight"
|
||||
style="@style/MoneroText.Monospace.Mnemonic"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/data_top"
|
||||
android:background="@drawable/backgound_seed"
|
||||
android:textAlignment="center"
|
||||
tools:text="1,878,151" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/llPassword"
|
||||
android:layout_width="match_parent"
|
||||
|
@@ -20,21 +20,46 @@
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp" />
|
||||
|
||||
<android.support.design.widget.TextInputLayout
|
||||
android:id="@+id/etAddress"
|
||||
<RelativeLayout
|
||||
android:id="@+id/llAddress"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:errorEnabled="true">
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginBottom="4dp"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<android.support.design.widget.TextInputEditText
|
||||
style="@style/MoneroEdit"
|
||||
android:layout_width="match_parent"
|
||||
<android.support.design.widget.TextInputLayout
|
||||
android:id="@+id/etAddress"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/send_address_hint"
|
||||
android:imeOptions="actionNext"
|
||||
android:inputType="textMultiLine"
|
||||
android:textAlignment="textStart" />
|
||||
</android.support.design.widget.TextInputLayout>
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_toStartOf="@+id/bPasteAddress"
|
||||
app:counterEnabled="true"
|
||||
app:counterMaxLength="16"
|
||||
app:errorEnabled="true">
|
||||
|
||||
<android.support.design.widget.TextInputEditText
|
||||
style="@style/MoneroEdit"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="10"
|
||||
android:hint="@string/send_address_hint"
|
||||
android:imeOptions="actionNext"
|
||||
android:inputType="textMultiLine"
|
||||
android:textAlignment="textStart" />
|
||||
</android.support.design.widget.TextInputLayout>
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/bPasteAddress"
|
||||
style="@style/MoneroText.Button.Small"
|
||||
android:layout_width="56dp"
|
||||
android:layout_height="56dp"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginStart="8dp"
|
||||
android:background="?android:selectableItemBackgroundBorderless"
|
||||
android:src="@drawable/ic_content_paste_orange_24dp" />
|
||||
</RelativeLayout>
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
|
@@ -15,6 +15,7 @@
|
||||
android:layout_centerInParent="true"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:padding="12dp"
|
||||
android:background="?android:attr/selectableItemBackgroundBorderless"
|
||||
android:gravity="center"
|
||||
android:src="@drawable/ic_bookmark_border_24dp" />
|
||||
@@ -24,6 +25,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_centerInParent="true"
|
||||
android:layout_margin="8dp"
|
||||
android:layout_toStartOf="@+id/ivPing"
|
||||
android:layout_toEndOf="@id/ibBookmark"
|
||||
|
54
app/src/main/res/values-cat/about.xml
Normal file
54
app/src/main/res/values-cat/about.xml
Normal file
@@ -0,0 +1,54 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="about_close">Tancar</string>
|
||||
<string name="about_whoami">Sóc en monerujo</string>
|
||||
<string name="about_version">Versió %1$s (%2$d)</string>
|
||||
|
||||
<string name="credits_text"><![CDATA[
|
||||
<b>Credits</b>
|
||||
<br/>
|
||||
m2049r, baltsar777, anhdres, keejef,
|
||||
rehrar, EarlOfEgo, ErCiccione et al.
|
||||
<br/><br/>
|
||||
<a href="https://monerujo.io/">monerujo.io</a>
|
||||
]]></string>
|
||||
|
||||
<string name="privacy_policy"><![CDATA[
|
||||
<h1>Política de Privacitat</h1>
|
||||
<p>Aquesta pàgina us informa de les nostres polítiques relatives a la recopilació,
|
||||
ús i divulgació de la informació personal que rebem dels usuaris de la nostra
|
||||
aplicació (monerujo: Monero Wallet).
|
||||
</p>
|
||||
<p>Mitjançant l'ús d'aquesta aplicació vostè accepta la recopilació i l’ús de la informació d’acord amb aquesta política.
|
||||
</p>
|
||||
<h2>Dades Recopilades</h2>
|
||||
<p>Les dades personals són qualsevol tipus de dades que puguin identificar un individu.
|
||||
</p>
|
||||
<p>Les claus i les adreces públiques de Monero són recollides i processades per l’aplicació de forma local per tal de processar les transaccions i transmetre-les a la xarxa Monero de forma encriptada.
|
||||
</p>
|
||||
<p>L'aplicació no recopila altres dades personals.</p>
|
||||
<p>Si utilitzeu la funcionalitat d'intercanvi (opcional), monerujo obté el canvi
|
||||
a través de l’API pública de coinmarketcap.com.
|
||||
Consulteu la seva política de privacitat a https://coinmarketcap.com/privacy per a més detalls sobre com es recullen les dades de les vostres peticions</p>
|
||||
<p>Si utilitzeu l’aplicació per pagar a adreces BTC, utilitzareu el servei XMR.TO.
|
||||
Consulteu la seva política de privacitat a https://xmr.to/ per obtenir més informació. Monerujo els envia l'adreça de destinació de BTC i la quantitat. La vostra IP també podrà ser recollida.</p>
|
||||
<h2>Permisos de la App</h2>
|
||||
<ul>
|
||||
<li>INTERNET : Connectar a la xarxa Monero mitjançant un Node Daemon de Monero</li>
|
||||
<li>READ_EXTERNAL_STORAGE : Llegir els arxius del portamonedes emmagatzemats al dispositiu</li>
|
||||
<li>WRITE_EXTERNAL_STORAGE : Escriure els arxius del portamonedes emmagatzemats al dispositiu</li>
|
||||
<li>WAKE_LOCK : Mantenir el dispositiu despert durant la sincronització</li>
|
||||
<li>CAMERA : Escanejar codis QR per rebre Monero</li>
|
||||
</ul>
|
||||
<h2>Canvis en aquesta Política de Privacitat</h2>
|
||||
<p>És possible que actualitzem aquesta política de privacitat de tant en tant. Li notificarem de qualsevol canvi publicant la nova política de privacitat a l’aplicació i al lloc web (www.monerujo.io)
|
||||
Us recomanem que reviseu aquesta política de privacitat periòdicament per conèixer els canvis.
|
||||
<p>Aquesta Política de Privacitat es va actualitzar per darrer cop: 10th November, 2017.
|
||||
</p>
|
||||
<h2>Contacti amb nosaltres</h2>
|
||||
<p>Si teniu alguna consulta sobre la nostra política de privadesa,
|
||||
o com es recullen i processen les vostres dades,
|
||||
si us plau envieu un correu electrònic a privacy@monerujo.io.
|
||||
</p>
|
||||
]]></string>
|
||||
</resources>
|
244
app/src/main/res/values-cat/help.xml
Normal file
244
app/src/main/res/values-cat/help.xml
Normal file
@@ -0,0 +1,244 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="help_create_new"><![CDATA[
|
||||
<h1>Crear Portamonedes - New</h1>
|
||||
<p>Per si necessiteu una nova adreça de Monero!</p>
|
||||
<p>Introduïu un nom i contrasenya únics del portamonedes.
|
||||
La contrasenya s’utilitza per protegir les dades del seu portamonedes en el dispositiu. Utilitzeu una contrasenya sòlida - encara millor si utiliza una frase.</p>
|
||||
<h2>Apunteu la vostra llavor mnemotècnica!</h2>
|
||||
<p>A la pantalla següent trobareu la vostra "Llavor Mnemotècnica" de 25 paraules.
|
||||
Aquestes són les úniques dades necessàries per a recuperar el vostre portamonedes i obtenir accés total als vostres fons.
|
||||
Mantenir-la segura i privada és molt important ja que permet que <em> qualsevol persona</em> tingui accés total als vostres fons!.</p>
|
||||
<p>Si perdeu la contrasenya del portamonedes encara podrieu recuperar-lo amb la llavor Mnemotècnica.</p>
|
||||
<p>La llavor Mnemotècnica tampoc no es pot canviar mai, i si és robada o compromesa d'alguna manera haureu de traslladar els vostres fons a un nou portamonedes (amb una nova llavor mnemotècnica). Per tant, es recomana que feu còpies de seguretat de la vostra llavor mnemotècnica escrivint-la i emmagatzemant-la a <em> múltiple </em> llocs de forma segura.</p>
|
||||
]]></string>
|
||||
|
||||
<string name="help_create_seed"><![CDATA[
|
||||
<h1>Crear Portamonedes - Llavor</h1>
|
||||
<p>Si ja teniu una adreça Monero i voleu recuperar les transaccions de la blockchain!</p>
|
||||
<p>Introduïu un nom i contrasenya únics del portamonedes.
|
||||
La contrasenya s’utilitza per protegir les dades del seu portamonedes en el dispositiu. Utilitzeu una contrasenya sòlida - encara millor si utiliza una frase.</p>
|
||||
<p>Introduïu la Llavor en el camp \"Llavor Mnemotècnica\".<p>
|
||||
<p>Introduïu el número de bloc de la primera transacció realitzada en aquesta adreça en el camp "Restaurar Alçada". També podeu utilitzar una data en el format AAAA-MM-DD. Si no esteu segurs, introduïu una data / alçada de bloc aproximada <em> abans </em> d'haver fer servir aquesta adreça del portamonedes.</p>
|
||||
]]></string>
|
||||
|
||||
<string name="help_create_ledger"><![CDATA[
|
||||
<h1>Crear Portamonedes - Ledger</h1>
|
||||
<p>Si voleu recuperar el vostre portamonedes desde un dispositiu Ledger Nano S!</p>
|
||||
<p>Les vostres claus secretes no surten mai del dispositiu Ledger, de manera que necessiteu que estigui connectat sempre que vulgueu accedir aal vostre portamonedes.</p>
|
||||
<p>Introduïu un nom i contrasenya únics del portamonedes. La contrasenya s’utilitza per protegir les dades de la seva cartera al dispositiu Android. Utilitzeu una contrasenya sòlida - encara millor si utiliza una frase.</p>
|
||||
<p>Introduïu el número de bloc de la primera transacció realitzada en aquesta adreça en el camp "Restaurar Alçada". També podeu utilitzar una data en el format AAAA-MM-DD. Si no esteu segurs, introduïu una data / alçada de bloc aproximada <em> abans </em> d'haver fer servir aquesta adreça del portamonedes.</p>
|
||||
]]></string>
|
||||
|
||||
<string name="help_create_keys"><![CDATA[
|
||||
<h1>Crear Portamonedes - Claus</h1>
|
||||
<p>Si voleu recuperar el vostre portamonedes fent servir les vostres claus!</p>
|
||||
<p>Introduïu un nom i contrasenya únics del portamonedes. La contrasenya s’utilitza per protegir les dades de la seva cartera al dispositiu. Utilitzeu una contrasenya sòlida - encara millor si utiliza una frase.<p>
|
||||
<p>Introduïu la vostra Adreça Monero en el camp \"Adreça Pública\" i ompliu \"Clau de Visualització\" i \"Clau de Despesa\" </p>
|
||||
<p>Introduïu el número de bloc de la primera transacció realitzada en aquesta adreça en el
|
||||
camp "Restaurar Alçada". També podeu utilitzar una data en el format AAAA-MM-DD. Si no esteu segurs, introduïu una data / alçada de bloc aproximada <em> abans </em> d'haver fer servir aquesta adreça del portamonedes.</p>
|
||||
]]></string>
|
||||
|
||||
<string name="help_create_view"><![CDATA[
|
||||
<h1>Crear Portamonedes - Només de Lectura</h1>
|
||||
<p>Si només voleu monitoritzar les transaccions entrants del portamonedes!</p>
|
||||
<p>Introduïu un nom i contrasenya únics del portamonedes. La contrasenya s’utilitza per protegir les dades de la seva cartera al dispositiu. Utilitzeu una contrasenya sòlida - encara millor si utiliza una frase.<p>
|
||||
<p>Introduïu la vostra Adreça Monero en el camp \"Adreça Pública\" i ompliu \"Clau de Visualització\".</p>
|
||||
<p>Introduïu el número de bloc de la primera transacció realitzada en aquesta adreça en el camp "Restaurar Alçada". També podeu utilitzar una data en el format AAAA-MM-DD. Si no esteu segurs, introduïu una data / alçada de bloc aproximada <em> abans </em> d'haver fer servir aquesta adreça del portamonedes.</p>
|
||||
]]></string>
|
||||
|
||||
<string name="help_details"><![CDATA[
|
||||
<h1>Detalls del portamonedes</h1>
|
||||
<h2>Adreça pública</h2>
|
||||
La vostra adreça pública és com el vostre número de compte bancari que podeu compartir amb qualsevol persona sense haver de tenir por de perdre el vostres Monero. La gent enviarà Monero al seu portamonedes mitjançant aquesta adreça.
|
||||
<h2>Clau Mnemotècnica</h2>
|
||||
Aquestes són les úniques dades necessàries per a recuperar el vostre portamonedes i obtenir accés total als vostres fons.
|
||||
Mantenir-la segura i privada és molt important ja que permet que <em> qualsevol persona</em> tingui accés total als vostres fons! Si no us heu escrit en cap lloc segur, feu-ho!
|
||||
<h2>Contrasenya de Recuperació d'Arxius del Portamonedes</h2>
|
||||
Assegureu-vos que heu escrit aquesta contrasenya. Si restabliu el dispositiu o desinstal·leu l’aplicació, la necessitarà per tornar a accedir al seu portamonedes.<br/>
|
||||
<h3>CrAzYsenya</h3>
|
||||
Si la contrasenya que es mostra aquí és de 52 caràcters alfanumèrics en grups de 4 - felicitats!
|
||||
Els fitxers del portamonedes estan protegits amb una clau de 256 bits generada per la funció de seguretat del vostre dispositiu basades en la contrasenya que heu triat (durant la creació o al canviar-la). Això ho fa extremadament difícil de piratejar!<br/>
|
||||
Aquesta opció és obligatoria per a tots els nous portamonedes.
|
||||
<h3>Contrasenya de Llegat</h3>
|
||||
Si veieu la vostra contrasenya aquí, els fitxers del portamonedes no estan tan segurs com quan s'utilitza la CrAzYsenya. Per solucionar-ho, seleccioneu \"Canviar Contrasenya\" des del menú. Després d'entrar una nova contrasenya (potser fins i tot la mateixa que abans) l’aplicació generarà una CrAzYsenya per a protegir els vostres arxius del portamonedes. Anoteu-la!
|
||||
<h3>CrAzYsenya del Portamonedes</h3>
|
||||
Si mai necessiteu tornar a instal·lar Monerujo (per exemple, després de restablir el telèfon o canviar-lo per un de nou) o voleu utilitzar els arxius del portamonedes en un altre dispositiu o PC, cal que ho feu utilitzant aquesta Contrasenya de Recuperació (CrAzYsenya) per tornar a accedir al vostre portamonedes. <br/>
|
||||
En seleccionar \"Canviar Contrasenya\" des del menú, podeu triar una nova contrasenya. Aneu amb compte que això generarà una nova Contrasenya de Recuperació (CrAzYsenya). Anoteu-la!
|
||||
<h2>Clau de Visualització</h2>
|
||||
La vostra clau de visualització es pot utilitzar per monitoritzar les transaccions entrants al vostre portamonedes sense donar-ne permís per gastar els fons a dins seu.
|
||||
<h2>Clau de Despesa</h2>
|
||||
La vostra clau de despesa permet a qualsevol persona gastar els Monero associats al seu portamonedes, així que no ho compartiu amb ningú, mantingueu-la segura com la vostra Llavor Mnemotècnica.
|
||||
]]></string>
|
||||
|
||||
<string name="help_list"><![CDATA[
|
||||
<h1>Llista de Portamonedes</h1>
|
||||
<h2>Node</h2>
|
||||
<p>Monerujo utilitza un node remot per comunicar-se amb la xarxa Monero sense necessitat
|
||||
de descarregar i emmagatzemar una còpia de tota la blockchain sencera. Podeu trobar una llista dels nodes remots més populars o aprendre a configurar el vostre propi node remot aquí https://moneroworld.com/<p>
|
||||
<p>Monerujo té alguns Nodes remots incorporats. Se'n recorda dels últims cinc nodes empleats.</p>
|
||||
<h2>Portamonedes</h2>
|
||||
<p>Aquí podeu veure els portamonedes. Es troben a la carpeta <tt> monerujo </tt>
|
||||
dins l’emmagatzematge intern del dispositiu. Podeu utilitzar una aplicació d’exploració d'arxius per veure'ls. Haurieu de fer còpies de seguretat d’aquesta carpeta de manera regular en un emmagatzematge extern al dispositiu en cas que el vostre dispositiu exploti o el robin.</p>
|
||||
<p>Seleccioneu una portamonedes per obrir-lo o premeu el botó "+" per crear-ne un de nou.
|
||||
O seleccioneu una de les operacions del portamonedes:</p>
|
||||
<h3>Detalls</h3>
|
||||
<p>Mostra els detalls del portamonedes, la llavor i les seves claus.</p>
|
||||
<h3>Rebre</h3>
|
||||
<p>Crea un codi QR per rebre Moneroj.</p>
|
||||
<h3>Canvi de Nom</h3>
|
||||
<p>Canvia el nom del portamonedes. El canvi de nom no afecta a les còpies de seguretat.</p>
|
||||
<h3>Còpia de Seguretat</h3>
|
||||
<p>Feu una còpia del portamonedes en la carpeta <tt> backups </tt> dins del <tt> monerujo </tt>
|
||||
per a sobreescriure còpies anteriors.</p>
|
||||
<h3>Arxiu</h3>
|
||||
<p>Feu una còpia de seguretat i a continuació elimineu el portamonedes. La còpia es mantindrà a la carpeta <tt> backups </tt>. Si ja no necessiteu les vostres còpies de seguretat les haureu d’eliminar amb un explorador d'arxius o una aplicació segura.</p>
|
||||
]]></string>
|
||||
|
||||
<string name="help_tx_details"><![CDATA[
|
||||
<h1>Detalls de Transacció</h1>
|
||||
<h2>Destí</h2>
|
||||
Aquesta és l'adreça pública del portamonedes on esteu enviant els Monero.
|
||||
<h2>ID de Pagament</h2>
|
||||
Podeu utilitzar un ID de pagament per identificar el motiu pel qual heu enviat a Monero entre dues parts. Això és totalment opcional i privat. Per exemple, això pot permetre a una empresa associar la transacció amb un article que heu comprat.
|
||||
<h2>ID de Transacció</h2>
|
||||
Aquest és el vostre ID de transacció que podeu utilitzar per identificar la vostra transacció oculta en un Explorador de Blockchain de Monero com <a href="https:// xmrchain.net/"> https://xmrchain.net/ </a>
|
||||
<h2>Clau de Transacció</h2>
|
||||
Aquesta és la vostra clau privada de transacció, manteniu-la segureta ja que mostrar-la a tercers els revelia quina signatura dins un anell és la vostra, fent que la vostra transacció sigui transparent.
|
||||
<h2>Bloc</h2>
|
||||
Aquest és el bloc de la cadena de Monero on la vostra transacció ha estat inclosa.
|
||||
]]></string>
|
||||
|
||||
<string name="help_send"><![CDATA[
|
||||
<h1>Enviar</h1>
|
||||
<h2>Adreça del Receptor</h2>
|
||||
<p>Aquesta és l'adreça pública del portamonedes a la qual esteu enviant Moneroj. Podeu copiar-la al porta-retalls, escanejar un codi QR o introduir-la manualment. Assegureu- vos de confirmar-ho a consciencia i que no estigueu enviant monedes a la direcció incorrecta.</p>
|
||||
<p>A més d’utilitzar una adreça XMR, també podeu utilitzar
|
||||
<ul>
|
||||
<li>un OpenAlias per XMR o BTC</li>
|
||||
<li>una adreça BTC</li>
|
||||
<li>un bitcoin: URI (inclòs BIP70 com bitpay)</li>
|
||||
</u>
|
||||
Tingueu en compte que l’enviament de BTC es duu a terme a través del servei XMR.TO (consulteu https://xmr.to per a més detalls). Consulteu la secció sobre l’enviament de BTC més avall.</p>
|
||||
<h2>ID de Pagament</h2>
|
||||
<p>Podeu utilitzar un ID de pagament per identificar el motiu pel qual heu enviat a Monero entre dues parts. Això és totalment opcional i privat. Per exemple, això pot permetre a una empresa associar la transacció amb un article que heu comprat.<p>
|
||||
<h1>Enviant BTC</h1>
|
||||
<h2>XMR.TO</h2>
|
||||
<p>XMR.TO és un servei de tercers que fa proporciona el canvi de Monero a Bitcoin.
|
||||
Nosaltres fem servir l'API XMR.TO per integrar els pagaments de Bitcoin a Monerujo. Si us plau, doneu un cop d'ull a https://xmr.to i decidiu vosaltres mateixos si és una cosa que volgueu utilitzar. L'equip de Monerujo no està associat amb XMR.TO i no pot oferir assistència amb el seu servei.</p>
|
||||
<h2>Tipus de Canvi XMR.TO<h2>
|
||||
<p>A la pantalla \"Quantitat\" es mostraran els paràmetres actuals del servei XMR.TO. Aquests
|
||||
inclouen el tipus de canvi actual, així com els límits de BTC superiors i inferiors. Tingueu en compte que la tarifa no està garantida en aquell mateix moment. També veureu
|
||||
la quantitat fins a la qual la transacció BTC s’executarà instantàniament sense esperar
|
||||
a confirmacions de XMR (consulteu les preguntes freqüents sobre XMR.TO per obtenir més informació). Tingueu en compte que el servei XMR.TO no suposa càrrecs addicionals: oi que mola?</p>
|
||||
<h2>Ordre de compra XMR.TO<h2>
|
||||
<p>A la pantalla \"Confirmar\", veureu l’ordre de compra XMR.TO real. Aquesta comanda és vàlida per a
|
||||
un temps limitat: és possible que veieu un compte enrere en el botó \"Gastar\". El tipus de canvi pot
|
||||
ser diferent del mostrat en pantalles anteriors.</p>
|
||||
<h2>Clau Secreta XMR.TO<h2>
|
||||
<p>Com que Monerujo només gestiona la part Monero de la vostra transacció, la vostra clau secreta per XMR.TO es pot utilitzar per fer el seguiment de la part de Bitcoin de la vostra comanda a la pàgina principal de XMR.TO.</p>
|
||||
<p>Tingueu en compte que aquesta clau secreta només és vàlida durant 24 hores després que la transacció
|
||||
ha començat!</p>
|
||||
<h2>Compte enrere XMR.TO!</h2>
|
||||
<p>Una vegada el compte enrere arribi a zero haureu d’obtenir una nova sol·licitud de XMR.TO tornant enrere al pas anterior i després tornar a la pantalla de \"Confirmar\".</p>
|
||||
]]></string>
|
||||
|
||||
<string name="help_xmrto"><![CDATA[
|
||||
<h1>Enviant BTC</h1>
|
||||
<h2>XMR.TO</h2>
|
||||
<p>XMR.TO és un servei de tercers que fa proporciona el canvi de Monero a Bitcoin.
|
||||
Nosaltres fem servir l'API XMR.TO per integrar els pagaments de Bitcoin a Monerujo. Si us plau, doneu un cop d'ull a https://xmr.to i decidiu vosaltres mateixos si és una cosa que volgueu utilitzar. L'equip de Monerujo no està associat amb XMR.TO i no pot oferir assistència amb el seu servei.</p>
|
||||
<h2>Tipus de Canvi XMR.TO<h2>
|
||||
<p>A la pantalla \"Quantitat\" es mostraran els paràmetres actuals del servei XMR.TO. Aquests
|
||||
inclouen el tipus de canvi actual, així com els límits de BTC superiors i inferiors. Tingueu en compte que la tarifa no està garantida en aquell mateix moment. També veureu
|
||||
la quantitat fins a la qual la transacció BTC s’executarà instantàniament sense esperar
|
||||
a confirmacions de XMR (consulteu les preguntes freqüents sobre XMR.TO per obtenir més informació). Tingueu en compte que el servei XMR.TO no suposa càrrecs addicionals: oi que mola?</p>
|
||||
<h2>Ordre de compra XMR.TO<h2>
|
||||
<p>A la pantalla \"Confirmar\", veureu l’ordre de compra XMR.TO real. Aquesta comanda és vàlida per a
|
||||
un temps limitat: és possible que veieu un compte enrere en el botó \"Gastar\". El tipus de canvi pot
|
||||
ser diferent del mostrat en pantalles anteriors.</p>
|
||||
<h2>Clau Secreta XMR.TO<h2>
|
||||
<p>Com que Monerujo només gestiona la part Monero de la vostra transacció, la vostra clau secreta per XMR.TO es pot utilitzar per fer el seguiment de la part de Bitcoin de la vostra comanda a la pàgina principal de XMR.TO.</p>
|
||||
<p>Tingueu en compte que aquesta clau secreta només és vàlida durant 24 hores després que la transacció
|
||||
ha començat!</p>
|
||||
<h2>Compte enrere XMR.TO!</h2>
|
||||
<p>Una vegada el compte enrere arribi a zero haureu d’obtenir una nova sol·licitud de XMR.TO tornant enrere al pas anterior i després tornar a la pantalla de \"Confirmar\".</p>
|
||||
]]></string>
|
||||
|
||||
<string name="help_wallet"><![CDATA[
|
||||
<h1>El Portamonedes</h1>
|
||||
<h2>Mode de carrer</h2>
|
||||
<p>El mode de carrer es pot habilitar / desactivar des del menú o a la icona principal de Gunther. En aquest mode, el vostre balanç no es mostra a cap pantalla perquè pugueu utilitzar la vostra cartera amb seguretat al carrer, al pub o qualsevol lloc públic. Les transaccions anteriors també estan ocultes. Es mostraran les noves transaccions perquè pogueu veure que heu enviat / rebut els vostres estimats Moneroj!</p>
|
||||
<h2>Escanejant</h2>
|
||||
Perquè a Monero li agrada mantenir les coses privades, cada cop que obri un portamonedes Monerujo hem d'escanejar la blockchain per veure si s'han enviat nous moneroj al seu portamonedes. Això només emmagatzema l'informació al telèfon que pertany al seu portamonedes. De vegades pot trigar una estona perquè no s’ha sincronitzat en molt de temps.
|
||||
<h2>El Balanç</h2>
|
||||
<p><b>Ajuda! El balanç del meu portamonedes ha desaparegut o consta com a no confirmat!</b><br/>
|
||||
No patiu! Quan envieu fons desde el vostre portamonedes part del balanç apareixerà com a no confirmat de forma temporal.
|
||||
Això succeeix pel fet de com Monero és intercanviat a través de la blockchain i com es produeix el canvi.
|
||||
Podeu llegir més sobre el canvi a https://getmonero.org/resources/moneropedia/change.html
|
||||
<h2>Llista de Transacció</h2>
|
||||
<p>Llistat de les transaccions del portamonedes. Els portamonedes de visualització només mostraran les transaccions entrants.</p>
|
||||
]]></string>
|
||||
|
||||
<string name="help_node"><![CDATA[
|
||||
<h1>Nodes</h1>
|
||||
<h2>TL;DR</h2>
|
||||
<p>Actualitzeu la llista de nodes prement cap avall; marqueu 3–5 nodes per permetre a Monerujo
|
||||
triar el millor per a tu!</p>
|
||||
<h2>Què és un Node?</h2>
|
||||
<p>Monerujo utilitza un Node Remot (de vegades també anomenat daemon) per comunicar-se
|
||||
la xarxa Monero sense haver de descarregar i emmagatzemar una còpia de
|
||||
tota la blockchain mateixa.<p>
|
||||
<h2>Llista de Nodes</h2>
|
||||
<p>Si la llista està buida, podeu afegir nous nodes manualment o deixar que Monerujo
|
||||
escanegi la xarxa per vostè. O ambdós. Llegiu …</p>
|
||||
<p>La llista de nodes mostra tots els nodes coneguts. A més, la marca de temps
|
||||
de l’últim bloc conegut per a cada node es mostra sota el nom del node. La icona
|
||||
que representa el temps de resposta del node
|
||||
(que indica el nivell de connectivitat estimat)
|
||||
es mostra al costat de cada node.</p>
|
||||
<p>Es pot marcar qualsevol node de la llista per utilitzar-lo més endevant.
|
||||
Es descartaràn els nodes que no hagin estat seleccionats.<p>
|
||||
<p>Monerujo escollirà el node òptim (marcat) cada vegada que l'utilitzeu.
|
||||
Això ho fa mitjançant la comprovació de l'alçada de bloc (com d'actualitzat
|
||||
està el node?), així com el temps de resposta (què tan ràpidament respon el node a les peticions?).</p>
|
||||
<p>La llista s’ordena per aquestes característiques, de manera que el node superior seria el que Monerujo
|
||||
triaria ara mateix. La part inferior de la llista mostraria els nodes més lents o no disponibles.</p>
|
||||
<h2>Afegir Node</h2>
|
||||
<p>Si premeu el botó "Afegir Node" a la part inferior, se us demanarà
|
||||
que introduïu els detalls del node al següent diàleg.
|
||||
El "Adreça" és el nom del servidor o adreça IP del node - aquesta és la única
|
||||
entrada obligatòria.
|
||||
Introduïu el "Port" si el node s'executa en un port no predeterminat (per exemple, 18089).
|
||||
També podeu anomenar opcionalment el node, de manera que el pugueu identificar més fàcilment més endavant.
|
||||
Alguns nodes necessiten credencials per utilitzar-los. Introduïu el nom d’usuari i
|
||||
contrasenya proporcionats als camps corresponents. Ara podeu "Test" aquesta configuració.
|
||||
Els "Resultats de les Proves" mostraran l'alçada de bloc, el temps de resposta i l'IP real.
|
||||
El resultat també pot ser un error - generalment perquè el nom del servidor proporcionat no és
|
||||
accessible dins d'un temps raonable o les credencials són incorrectes.
|
||||
O la combinació de nom del servidor/port no apunta cap a un node real de Monero!
|
||||
Un cop aprovada la prova (sense error), ja estás llest per prémer "D'acord" per desar iamp;
|
||||
marcar aquest node.</p>
|
||||
<h2>Escanejar Nodes</h2>
|
||||
<p>A més, podeu escanejar la xarxa per buscar nodes. Monerujo començarà
|
||||
escanejant la xarxa per als nodes remots al port 18089. Començarà per preguntar als vostres
|
||||
nodes marcats per altres companys de la xarxa P2P de Monero, i després continuarà
|
||||
preguntant-los per als seus companys, etc. Si no teniu cap node marcat
|
||||
(o no ens informen sobre els seus companys),
|
||||
Monerujo anirà directament als nodes de llavor de Monero codificats a dins de Monero.
|
||||
L’escaneig s’atura quan troba un total de 10 nodes remots.</p>
|
||||
]]></string>
|
||||
|
||||
<string name="help_uri"><![CDATA[
|
||||
<h1>Fer servir un enllaç de pagament</h1>
|
||||
<p>Heu iniciat monerujo amb un enllaç de pagament. Per enviar fons, feu el següent:</p>
|
||||
<p>
|
||||
1. Obrir el portamonedes desde la qual voleu gastar els fons<br>
|
||||
2. Espereu fins que es sincronitzi el portamonedes i el botó de "Donar" apareixi<br>
|
||||
3. Premeu el botó de "Donar"
|
||||
</p>
|
||||
<p>Els detalls de pagament es completaran. Comproveu-les i continueu com a qualsevol altra transacció.</p>
|
||||
]]></string>
|
||||
|
||||
<string name="help_ok">Ja ho tinc!</string> <!-- Note: "Got it" as in "I understand this" -->
|
||||
</resources>
|
386
app/src/main/res/values-cat/strings.xml
Normal file
386
app/src/main/res/values-cat/strings.xml
Normal file
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user