mirror of
https://github.com/m2049r/xmrwallet
synced 2025-09-11 14:40:50 +02:00
Compare commits
16 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
de8de02f9f | ||
![]() |
06456e33e4 | ||
![]() |
d97b36aa44 | ||
![]() |
8fa06e5b37 | ||
![]() |
8d95de828b | ||
![]() |
93a7be0452 | ||
![]() |
25c8ec1229 | ||
![]() |
0bf0444dce | ||
![]() |
b74f9c6bd7 | ||
![]() |
f843bb1685 | ||
![]() |
7d9d49c29e | ||
![]() |
4ca9328949 | ||
![]() |
08b5a87f19 | ||
![]() |
445d8acc38 | ||
![]() |
9385ac8c31 | ||
![]() |
4c7ebd8402 |
@@ -7,8 +7,8 @@ android {
|
|||||||
applicationId "com.m2049r.xmrwallet"
|
applicationId "com.m2049r.xmrwallet"
|
||||||
minSdkVersion 21
|
minSdkVersion 21
|
||||||
targetSdkVersion 28
|
targetSdkVersion 28
|
||||||
versionCode 165
|
versionCode 172
|
||||||
versionName "1.10.15 'Node-O-matiC'"
|
versionName "1.11.2 'Chernushka'"
|
||||||
|
|
||||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||||
externalNativeBuild {
|
externalNativeBuild {
|
||||||
|
@@ -26,14 +26,14 @@
|
|||||||
android:configChanges="orientation|keyboardHidden"
|
android:configChanges="orientation|keyboardHidden"
|
||||||
android:label="@string/wallet_activity_name"
|
android:label="@string/wallet_activity_name"
|
||||||
android:launchMode="singleTask"
|
android:launchMode="singleTask"
|
||||||
android:screenOrientation="portrait" />
|
android:screenOrientation="behind" />
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".LoginActivity"
|
android:name=".LoginActivity"
|
||||||
android:configChanges="orientation|keyboardHidden"
|
android:configChanges="orientation|keyboardHidden"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
android:launchMode="singleTop"
|
android:launchMode="singleTop"
|
||||||
android:screenOrientation="portrait">
|
android:screenOrientation="locked">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
<category android:name="android.intent.category.LAUNCHER" />
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
@@ -42,6 +42,22 @@
|
|||||||
<action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
|
<action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
|
|
||||||
|
<intent-filter android:label="@string/app_name">
|
||||||
|
<action android:name="android.intent.action.VIEW" />
|
||||||
|
<data android:scheme="monero" />
|
||||||
|
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
<category android:name="android.intent.category.BROWSABLE" />
|
||||||
|
</intent-filter>
|
||||||
|
|
||||||
|
<intent-filter android:label="@string/app_name">
|
||||||
|
<action android:name="android.intent.action.VIEW" />
|
||||||
|
<data android:scheme="bitcoin" />
|
||||||
|
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
<category android:name="android.intent.category.BROWSABLE" />
|
||||||
|
</intent-filter>
|
||||||
|
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
|
android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
|
||||||
android:resource="@xml/usb_device_filter" />
|
android:resource="@xml/usb_device_filter" />
|
||||||
@@ -52,5 +68,15 @@
|
|||||||
android:description="@string/service_description"
|
android:description="@string/service_description"
|
||||||
android:exported="false"
|
android:exported="false"
|
||||||
android:label="Monero Wallet Service" />
|
android:label="Monero Wallet Service" />
|
||||||
|
|
||||||
|
<provider
|
||||||
|
android:name="android.support.v4.content.FileProvider"
|
||||||
|
android:authorities="${applicationId}.fileprovider"
|
||||||
|
android:exported="false"
|
||||||
|
android:grantUriPermissions="true">
|
||||||
|
<meta-data
|
||||||
|
android:name="android.support.FILE_PROVIDER_PATHS"
|
||||||
|
android:resource="@xml/filepaths" />
|
||||||
|
</provider>
|
||||||
</application>
|
</application>
|
||||||
</manifest>
|
</manifest>
|
@@ -60,14 +60,14 @@ enum {
|
|||||||
HASH_DATA_AREA = 136
|
HASH_DATA_AREA = 136
|
||||||
};
|
};
|
||||||
|
|
||||||
void cn_slow_hash(const void *data, size_t length, char *hash, int variant, int prehashed);
|
void cn_slow_hash(const void *data, size_t length, char *hash, int variant, int prehashed, uint64_t height);
|
||||||
|
|
||||||
inline void slow_hash(const void *data, const size_t length, char *hash) {
|
inline void slow_hash(const void *data, const size_t length, char *hash) {
|
||||||
cn_slow_hash(data, length, hash, 0 /* variant */, 0/*prehashed*/);
|
cn_slow_hash(data, length, hash, 0 /*variant*/, 0 /*prehashed*/, 0 /*height*/);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void slow_hash_broken(const void *data, char *hash, int variant) {
|
inline void slow_hash_broken(const void *data, char *hash, int variant) {
|
||||||
cn_slow_hash(data, 200 /*sizeof(union hash_state)*/, hash, variant, 1 /*prehashed*/);
|
cn_slow_hash(data, 200 /*sizeof(union hash_state)*/, hash, variant, 1 /*prehashed*/, 0 /*height*/);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
@@ -173,10 +173,10 @@ public class LevinReader {
|
|||||||
|
|
||||||
// this should be in LittleEndianDataInputStream because it has little
|
// this should be in LittleEndianDataInputStream because it has little
|
||||||
// endian logic
|
// endian logic
|
||||||
private long readRest(int firstByte, int bytes) throws IOException {
|
private long readRest(final int firstByte, final int bytes) throws IOException {
|
||||||
long result = firstByte;
|
long result = firstByte;
|
||||||
for (int i = 0; i < bytes; i++) {
|
for (int i = 1; i < bytes + 1; i++) {
|
||||||
result = result + (in.readUnsignedByte() << 8);
|
result = result + (((long) in.readUnsignedByte()) << (8 * i));
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@@ -95,7 +95,6 @@ public class GenerateFragment extends Fragment {
|
|||||||
etWalletRestoreHeight = view.findViewById(R.id.etWalletRestoreHeight);
|
etWalletRestoreHeight = view.findViewById(R.id.etWalletRestoreHeight);
|
||||||
bGenerate = view.findViewById(R.id.bGenerate);
|
bGenerate = view.findViewById(R.id.bGenerate);
|
||||||
|
|
||||||
etWalletMnemonic.getEditText().setRawInputType(InputType.TYPE_CLASS_TEXT);
|
|
||||||
etWalletAddress.getEditText().setRawInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
|
etWalletAddress.getEditText().setRawInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
|
||||||
etWalletViewKey.getEditText().setRawInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
|
etWalletViewKey.getEditText().setRawInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
|
||||||
etWalletSpendKey.getEditText().setRawInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
|
etWalletSpendKey.getEditText().setRawInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
|
||||||
|
@@ -269,7 +269,11 @@ public class LoginActivity extends BaseActivity
|
|||||||
} else {
|
} else {
|
||||||
Timber.i("Waiting for permissions");
|
Timber.i("Waiting for permissions");
|
||||||
}
|
}
|
||||||
processUsbIntent(getIntent());
|
|
||||||
|
// try intents
|
||||||
|
Intent intent = getIntent();
|
||||||
|
if (!processUsbIntent(intent))
|
||||||
|
processUriIntent(intent);
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean checkServiceRunning() {
|
boolean checkServiceRunning() {
|
||||||
@@ -716,6 +720,10 @@ public class LoginActivity extends BaseActivity
|
|||||||
intent.putExtra(WalletActivity.REQUEST_PW, walletPassword);
|
intent.putExtra(WalletActivity.REQUEST_PW, walletPassword);
|
||||||
intent.putExtra(WalletActivity.REQUEST_FINGERPRINT_USED, fingerprintUsed);
|
intent.putExtra(WalletActivity.REQUEST_FINGERPRINT_USED, fingerprintUsed);
|
||||||
intent.putExtra(WalletActivity.REQUEST_STREETMODE, streetmode);
|
intent.putExtra(WalletActivity.REQUEST_STREETMODE, streetmode);
|
||||||
|
if (uri != null) {
|
||||||
|
intent.putExtra(WalletActivity.REQUEST_URI, uri);
|
||||||
|
uri = null; // use only once
|
||||||
|
}
|
||||||
startActivity(intent);
|
startActivity(intent);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1353,30 +1361,31 @@ public class LoginActivity extends BaseActivity
|
|||||||
};
|
};
|
||||||
|
|
||||||
private void connectLedger(UsbManager usbManager, final UsbDevice usbDevice) {
|
private void connectLedger(UsbManager usbManager, final UsbDevice usbDevice) {
|
||||||
try {
|
if (Ledger.ENABLED)
|
||||||
Ledger.connect(usbManager, usbDevice);
|
try {
|
||||||
registerDetachReceiver();
|
Ledger.connect(usbManager, usbDevice);
|
||||||
onLedgerAction();
|
registerDetachReceiver();
|
||||||
runOnUiThread(new Runnable() {
|
onLedgerAction();
|
||||||
@Override
|
runOnUiThread(new Runnable() {
|
||||||
public void run() {
|
@Override
|
||||||
Toast.makeText(LoginActivity.this,
|
public void run() {
|
||||||
getString(R.string.toast_ledger_attached, usbDevice.getProductName()),
|
Toast.makeText(LoginActivity.this,
|
||||||
Toast.LENGTH_SHORT)
|
getString(R.string.toast_ledger_attached, usbDevice.getProductName()),
|
||||||
.show();
|
Toast.LENGTH_SHORT)
|
||||||
}
|
.show();
|
||||||
});
|
}
|
||||||
} catch (IOException ex) {
|
});
|
||||||
runOnUiThread(new Runnable() {
|
} catch (IOException ex) {
|
||||||
@Override
|
runOnUiThread(new Runnable() {
|
||||||
public void run() {
|
@Override
|
||||||
Toast.makeText(LoginActivity.this,
|
public void run() {
|
||||||
getString(R.string.open_wallet_ledger_missing),
|
Toast.makeText(LoginActivity.this,
|
||||||
Toast.LENGTH_SHORT)
|
getString(R.string.open_wallet_ledger_missing),
|
||||||
.show();
|
Toast.LENGTH_SHORT)
|
||||||
}
|
.show();
|
||||||
});
|
}
|
||||||
}
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -1385,7 +1394,7 @@ public class LoginActivity extends BaseActivity
|
|||||||
processUsbIntent(intent);
|
processUsbIntent(intent);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void processUsbIntent(Intent intent) {
|
private boolean processUsbIntent(Intent intent) {
|
||||||
String action = intent.getAction();
|
String action = intent.getAction();
|
||||||
if (UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(action)) {
|
if (UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(action)) {
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
@@ -1398,6 +1407,21 @@ public class LoginActivity extends BaseActivity
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String uri = null;
|
||||||
|
|
||||||
|
private void processUriIntent(Intent intent) {
|
||||||
|
String action = intent.getAction();
|
||||||
|
if (Intent.ACTION_VIEW.equals(action)) {
|
||||||
|
synchronized (this) {
|
||||||
|
uri = intent.getDataString();
|
||||||
|
Timber.d("URI Intent %s", uri);
|
||||||
|
HelpFragment.display(getSupportFragmentManager(), R.string.help_uri);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -17,19 +17,28 @@
|
|||||||
package com.m2049r.xmrwallet;
|
package com.m2049r.xmrwallet;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
import android.graphics.Canvas;
|
import android.graphics.Canvas;
|
||||||
import android.graphics.drawable.BitmapDrawable;
|
import android.graphics.drawable.BitmapDrawable;
|
||||||
|
import android.net.Uri;
|
||||||
import android.nfc.NfcManager;
|
import android.nfc.NfcManager;
|
||||||
import android.os.AsyncTask;
|
import android.os.AsyncTask;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
import android.support.design.widget.TextInputLayout;
|
import android.support.design.widget.TextInputLayout;
|
||||||
import android.support.v4.app.Fragment;
|
import android.support.v4.app.Fragment;
|
||||||
|
import android.support.v4.content.FileProvider;
|
||||||
|
import android.support.v4.view.MenuItemCompat;
|
||||||
|
import android.support.v7.widget.ShareActionProvider;
|
||||||
import android.text.Editable;
|
import android.text.Editable;
|
||||||
import android.text.InputType;
|
import android.text.InputType;
|
||||||
import android.text.TextWatcher;
|
import android.text.TextWatcher;
|
||||||
import android.view.KeyEvent;
|
import android.view.KeyEvent;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.Menu;
|
||||||
|
import android.view.MenuInflater;
|
||||||
|
import android.view.MenuItem;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.view.inputmethod.EditorInfo;
|
import android.view.inputmethod.EditorInfo;
|
||||||
@@ -56,6 +65,9 @@ import com.m2049r.xmrwallet.util.MoneroThreadPoolExecutor;
|
|||||||
import com.m2049r.xmrwallet.widget.ExchangeView;
|
import com.m2049r.xmrwallet.widget.ExchangeView;
|
||||||
import com.m2049r.xmrwallet.widget.Toolbar;
|
import com.m2049r.xmrwallet.widget.Toolbar;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@@ -69,8 +81,8 @@ public class ReceiveFragment extends Fragment {
|
|||||||
private TextInputLayout etNotes;
|
private TextInputLayout etNotes;
|
||||||
private ExchangeView evAmount;
|
private ExchangeView evAmount;
|
||||||
private TextView tvQrCode;
|
private TextView tvQrCode;
|
||||||
private ImageView qrCode;
|
private ImageView ivQrCode;
|
||||||
private ImageView qrCodeFull;
|
private ImageView ivQrCodeFull;
|
||||||
private EditText etDummy;
|
private EditText etDummy;
|
||||||
private ImageButton bCopyAddress;
|
private ImageButton bCopyAddress;
|
||||||
private Button bSubaddress;
|
private Button bSubaddress;
|
||||||
@@ -97,9 +109,9 @@ public class ReceiveFragment extends Fragment {
|
|||||||
tvAddress = view.findViewById(R.id.tvAddress);
|
tvAddress = view.findViewById(R.id.tvAddress);
|
||||||
etNotes = view.findViewById(R.id.etNotes);
|
etNotes = view.findViewById(R.id.etNotes);
|
||||||
evAmount = view.findViewById(R.id.evAmount);
|
evAmount = view.findViewById(R.id.evAmount);
|
||||||
qrCode = view.findViewById(R.id.qrCode);
|
ivQrCode = view.findViewById(R.id.qrCode);
|
||||||
tvQrCode = view.findViewById(R.id.tvQrCode);
|
tvQrCode = view.findViewById(R.id.tvQrCode);
|
||||||
qrCodeFull = view.findViewById(R.id.qrCodeFull);
|
ivQrCodeFull = view.findViewById(R.id.qrCodeFull);
|
||||||
etDummy = view.findViewById(R.id.etDummy);
|
etDummy = view.findViewById(R.id.etDummy);
|
||||||
bCopyAddress = view.findViewById(R.id.bCopyAddress);
|
bCopyAddress = view.findViewById(R.id.bCopyAddress);
|
||||||
bSubaddress = view.findViewById(R.id.bSubaddress);
|
bSubaddress = view.findViewById(R.id.bSubaddress);
|
||||||
@@ -178,25 +190,25 @@ public class ReceiveFragment extends Fragment {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
qrCode.setOnClickListener(new View.OnClickListener() {
|
ivQrCode.setOnClickListener(new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
Helper.hideKeyboard(getActivity());
|
Helper.hideKeyboard(getActivity());
|
||||||
etDummy.requestFocus();
|
etDummy.requestFocus();
|
||||||
if (qrValid) {
|
if (qrValid) {
|
||||||
qrCodeFull.setImageBitmap(((BitmapDrawable) qrCode.getDrawable()).getBitmap());
|
ivQrCodeFull.setImageBitmap(((BitmapDrawable) ivQrCode.getDrawable()).getBitmap());
|
||||||
qrCodeFull.setVisibility(View.VISIBLE);
|
ivQrCodeFull.setVisibility(View.VISIBLE);
|
||||||
} else {
|
} else {
|
||||||
evAmount.doExchange();
|
evAmount.doExchange();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
qrCodeFull.setOnClickListener(new View.OnClickListener() {
|
ivQrCodeFull.setOnClickListener(new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
qrCodeFull.setImageBitmap(null);
|
ivQrCodeFull.setImageBitmap(null);
|
||||||
qrCodeFull.setVisibility(View.GONE);
|
ivQrCodeFull.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -228,6 +240,81 @@ public class ReceiveFragment extends Fragment {
|
|||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
setHasOptionsMenu(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ShareActionProvider shareActionProvider;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreateOptionsMenu(Menu menu, final MenuInflater inflater) {
|
||||||
|
inflater.inflate(R.menu.receive_menu, menu);
|
||||||
|
super.onCreateOptionsMenu(menu, inflater);
|
||||||
|
|
||||||
|
// Locate MenuItem with ShareActionProvider
|
||||||
|
MenuItem item = menu.findItem(R.id.menu_item_share);
|
||||||
|
|
||||||
|
// Fetch and store ShareActionProvider
|
||||||
|
shareActionProvider = (ShareActionProvider) MenuItemCompat.getActionProvider(item);
|
||||||
|
|
||||||
|
shareActionProvider.setOnShareTargetSelectedListener(new ShareActionProvider.OnShareTargetSelectedListener() {
|
||||||
|
@Override
|
||||||
|
public boolean onShareTargetSelected(ShareActionProvider shareActionProvider, Intent intent) {
|
||||||
|
saveQrCode(); // save it only if we need it
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setShareIntent() {
|
||||||
|
if (shareActionProvider != null) {
|
||||||
|
if (qrValid) {
|
||||||
|
shareActionProvider.setShareIntent(getShareIntent());
|
||||||
|
} else {
|
||||||
|
shareActionProvider.setShareIntent(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void saveQrCode() {
|
||||||
|
if (!qrValid) throw new IllegalStateException("trying to save null qr code!");
|
||||||
|
|
||||||
|
File cachePath = new File(getActivity().getCacheDir(), "images");
|
||||||
|
if (!cachePath.exists())
|
||||||
|
if (!cachePath.mkdirs()) throw new IllegalStateException("cannot create images folder");
|
||||||
|
File png = new File(cachePath, "QR.png");
|
||||||
|
try {
|
||||||
|
FileOutputStream stream = new FileOutputStream(png);
|
||||||
|
Bitmap qrBitmap = ((BitmapDrawable) ivQrCode.getDrawable()).getBitmap();
|
||||||
|
qrBitmap.compress(Bitmap.CompressFormat.PNG, 100, stream);
|
||||||
|
stream.close();
|
||||||
|
} catch (IOException ex) {
|
||||||
|
Timber.e(ex);
|
||||||
|
// make sure we don't share an old qr code
|
||||||
|
if (!png.delete()) throw new IllegalStateException("cannot delete old qr code");
|
||||||
|
// if we manage to delete it, the URI points to nothing and the user gets a toast with the error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Intent getShareIntent() {
|
||||||
|
File imagePath = new File(getActivity().getCacheDir(), "images");
|
||||||
|
File png = new File(imagePath, "QR.png");
|
||||||
|
Uri contentUri = FileProvider.getUriForFile(getActivity(),
|
||||||
|
"com.m2049r.xmrwallet.fileprovider", png);
|
||||||
|
if (contentUri != null) {
|
||||||
|
Intent shareIntent = new Intent();
|
||||||
|
shareIntent.setAction(Intent.ACTION_SEND);
|
||||||
|
shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); // temp permission for receiving app to read this file
|
||||||
|
shareIntent.setDataAndType(contentUri, getActivity().getContentResolver().getType(contentUri));
|
||||||
|
shareIntent.putExtra(Intent.EXTRA_STREAM, contentUri);
|
||||||
|
shareIntent.putExtra(Intent.EXTRA_TEXT, bcData.getUriString());
|
||||||
|
return shareIntent;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
void enableSubaddressButton(boolean enable) {
|
void enableSubaddressButton(boolean enable) {
|
||||||
bSubaddress.setEnabled(enable);
|
bSubaddress.setEnabled(enable);
|
||||||
if (enable) {
|
if (enable) {
|
||||||
@@ -242,23 +329,23 @@ public class ReceiveFragment extends Fragment {
|
|||||||
Toast.makeText(getActivity(), getString(R.string.message_copy_address), Toast.LENGTH_SHORT).show();
|
Toast.makeText(getActivity(), getString(R.string.message_copy_address), Toast.LENGTH_SHORT).show();
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean qrValid = true;
|
private boolean qrValid = false;
|
||||||
|
|
||||||
void clearQR() {
|
void clearQR() {
|
||||||
if (qrValid) {
|
if (qrValid) {
|
||||||
qrCode.setImageBitmap(null);
|
ivQrCode.setImageBitmap(null);
|
||||||
qrValid = false;
|
qrValid = false;
|
||||||
|
setShareIntent();
|
||||||
if (isLoaded)
|
if (isLoaded)
|
||||||
tvQrCode.setVisibility(View.VISIBLE);
|
tvQrCode.setVisibility(View.VISIBLE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void setQR(Bitmap qr) {
|
void setQR(Bitmap qr) {
|
||||||
qrCode.setImageBitmap(qr);
|
ivQrCode.setImageBitmap(qr);
|
||||||
qrValid = true;
|
qrValid = true;
|
||||||
|
setShareIntent();
|
||||||
tvQrCode.setVisibility(View.GONE);
|
tvQrCode.setVisibility(View.GONE);
|
||||||
Helper.hideKeyboard(getActivity());
|
|
||||||
etDummy.requestFocus();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -392,7 +479,7 @@ public class ReceiveFragment extends Fragment {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
bcData = new BarcodeData(BarcodeData.Asset.XMR, address, null, notes, xmrAmount);
|
bcData = new BarcodeData(BarcodeData.Asset.XMR, address, null, notes, xmrAmount);
|
||||||
int size = Math.min(qrCode.getHeight(), qrCode.getWidth());
|
int size = Math.max(ivQrCode.getWidth(), ivQrCode.getHeight());
|
||||||
Bitmap qr = generate(bcData.getUriString(), size, size);
|
Bitmap qr = generate(bcData.getUriString(), size, size);
|
||||||
if (qr != null) {
|
if (qr != null) {
|
||||||
setQR(qr);
|
setQR(qr);
|
||||||
@@ -422,8 +509,8 @@ public class ReceiveFragment extends Fragment {
|
|||||||
Bitmap bitmap = Bitmap.createBitmap(pixels, 0, width, width, height, Bitmap.Config.RGB_565);
|
Bitmap bitmap = Bitmap.createBitmap(pixels, 0, width, width, height, Bitmap.Config.RGB_565);
|
||||||
bitmap = addLogo(bitmap);
|
bitmap = addLogo(bitmap);
|
||||||
return bitmap;
|
return bitmap;
|
||||||
} catch (WriterException e) {
|
} catch (WriterException ex) {
|
||||||
e.printStackTrace();
|
Timber.e(ex);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@@ -31,7 +31,7 @@ public abstract class SecureActivity extends AppCompatActivity {
|
|||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
// set FLAG_SECURE to prevent screenshots in Release Mode
|
// set FLAG_SECURE to prevent screenshots in Release Mode
|
||||||
if (!BuildConfig.DEBUG && !BuildConfig.FLAVOR_type.equals("alpha")) {
|
if (!(BuildConfig.DEBUG && BuildConfig.FLAVOR_type.equals("alpha"))) {
|
||||||
getWindow().setFlags(LayoutParams.FLAG_SECURE, LayoutParams.FLAG_SECURE);
|
getWindow().setFlags(LayoutParams.FLAG_SECURE, LayoutParams.FLAG_SECURE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -47,6 +47,7 @@ import android.widget.Toast;
|
|||||||
|
|
||||||
import com.m2049r.xmrwallet.data.BarcodeData;
|
import com.m2049r.xmrwallet.data.BarcodeData;
|
||||||
import com.m2049r.xmrwallet.data.TxData;
|
import com.m2049r.xmrwallet.data.TxData;
|
||||||
|
import com.m2049r.xmrwallet.data.UserNotes;
|
||||||
import com.m2049r.xmrwallet.dialog.CreditsFragment;
|
import com.m2049r.xmrwallet.dialog.CreditsFragment;
|
||||||
import com.m2049r.xmrwallet.dialog.HelpFragment;
|
import com.m2049r.xmrwallet.dialog.HelpFragment;
|
||||||
import com.m2049r.xmrwallet.fragment.send.SendAddressWizardFragment;
|
import com.m2049r.xmrwallet.fragment.send.SendAddressWizardFragment;
|
||||||
@@ -59,7 +60,6 @@ import com.m2049r.xmrwallet.model.WalletManager;
|
|||||||
import com.m2049r.xmrwallet.service.WalletService;
|
import com.m2049r.xmrwallet.service.WalletService;
|
||||||
import com.m2049r.xmrwallet.util.Helper;
|
import com.m2049r.xmrwallet.util.Helper;
|
||||||
import com.m2049r.xmrwallet.util.MoneroThreadPoolExecutor;
|
import com.m2049r.xmrwallet.util.MoneroThreadPoolExecutor;
|
||||||
import com.m2049r.xmrwallet.data.UserNotes;
|
|
||||||
import com.m2049r.xmrwallet.widget.Toolbar;
|
import com.m2049r.xmrwallet.widget.Toolbar;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -81,6 +81,7 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste
|
|||||||
public static final String REQUEST_PW = "pw";
|
public static final String REQUEST_PW = "pw";
|
||||||
public static final String REQUEST_FINGERPRINT_USED = "fingerprint";
|
public static final String REQUEST_FINGERPRINT_USED = "fingerprint";
|
||||||
public static final String REQUEST_STREETMODE = "streetmode";
|
public static final String REQUEST_STREETMODE = "streetmode";
|
||||||
|
public static final String REQUEST_URI = "uri";
|
||||||
|
|
||||||
private NavigationView accountsView;
|
private NavigationView accountsView;
|
||||||
private DrawerLayout drawer;
|
private DrawerLayout drawer;
|
||||||
@@ -92,6 +93,8 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste
|
|||||||
|
|
||||||
private String password;
|
private String password;
|
||||||
|
|
||||||
|
private String uri = null;
|
||||||
|
|
||||||
private long streetMode = 0;
|
private long streetMode = 0;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -191,6 +194,7 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste
|
|||||||
// we can set the streetmode height AFTER opening the wallet
|
// we can set the streetmode height AFTER opening the wallet
|
||||||
requestStreetMode = extras.getBoolean(REQUEST_STREETMODE);
|
requestStreetMode = extras.getBoolean(REQUEST_STREETMODE);
|
||||||
password = extras.getString(REQUEST_PW);
|
password = extras.getString(REQUEST_PW);
|
||||||
|
uri = extras.getString(REQUEST_URI);
|
||||||
connectWalletService(walletId, password);
|
connectWalletService(walletId, password);
|
||||||
} else {
|
} else {
|
||||||
finish();
|
finish();
|
||||||
@@ -512,7 +516,8 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onSendRequest() {
|
public void onSendRequest() {
|
||||||
replaceFragment(new SendFragment(), null, null);
|
replaceFragment(SendFragment.newInstance(uri), null, null);
|
||||||
|
uri = null; // only use uri once
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@@ -67,7 +67,7 @@ public class HelpFragment extends DialogFragment {
|
|||||||
|
|
||||||
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
|
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
|
||||||
builder.setView(view);
|
builder.setView(view);
|
||||||
builder.setNegativeButton(R.string.about_close,
|
builder.setNegativeButton(R.string.help_ok,
|
||||||
new DialogInterface.OnClickListener() {
|
new DialogInterface.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(DialogInterface dialog, int id) {
|
public void onClick(DialogInterface dialog, int id) {
|
||||||
|
@@ -22,11 +22,11 @@ import android.content.Context;
|
|||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.WindowManager;
|
||||||
import android.widget.FrameLayout;
|
|
||||||
import android.widget.ProgressBar;
|
import android.widget.ProgressBar;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import com.m2049r.xmrwallet.BuildConfig;
|
||||||
import com.m2049r.xmrwallet.R;
|
import com.m2049r.xmrwallet.R;
|
||||||
|
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
@@ -78,6 +78,11 @@ public class ProgressDialog extends AlertDialog {
|
|||||||
}
|
}
|
||||||
|
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
|
// set FLAG_SECURE to prevent screenshots in Release Mode
|
||||||
|
if (!(BuildConfig.DEBUG && BuildConfig.FLAVOR_type.equals("alpha"))) {
|
||||||
|
getWindow().setFlags(WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setProgress(int value, int max) {
|
public void setProgress(int value, int max) {
|
||||||
|
@@ -38,15 +38,16 @@ import android.widget.EditText;
|
|||||||
import com.m2049r.xmrwallet.OnBackPressedListener;
|
import com.m2049r.xmrwallet.OnBackPressedListener;
|
||||||
import com.m2049r.xmrwallet.OnUriScannedListener;
|
import com.m2049r.xmrwallet.OnUriScannedListener;
|
||||||
import com.m2049r.xmrwallet.R;
|
import com.m2049r.xmrwallet.R;
|
||||||
|
import com.m2049r.xmrwallet.WalletActivity;
|
||||||
import com.m2049r.xmrwallet.data.BarcodeData;
|
import com.m2049r.xmrwallet.data.BarcodeData;
|
||||||
import com.m2049r.xmrwallet.data.PendingTx;
|
import com.m2049r.xmrwallet.data.PendingTx;
|
||||||
import com.m2049r.xmrwallet.data.TxData;
|
import com.m2049r.xmrwallet.data.TxData;
|
||||||
import com.m2049r.xmrwallet.data.TxDataBtc;
|
import com.m2049r.xmrwallet.data.TxDataBtc;
|
||||||
|
import com.m2049r.xmrwallet.data.UserNotes;
|
||||||
import com.m2049r.xmrwallet.layout.SpendViewPager;
|
import com.m2049r.xmrwallet.layout.SpendViewPager;
|
||||||
import com.m2049r.xmrwallet.model.PendingTransaction;
|
import com.m2049r.xmrwallet.model.PendingTransaction;
|
||||||
import com.m2049r.xmrwallet.util.Helper;
|
import com.m2049r.xmrwallet.util.Helper;
|
||||||
import com.m2049r.xmrwallet.util.Notice;
|
import com.m2049r.xmrwallet.util.Notice;
|
||||||
import com.m2049r.xmrwallet.data.UserNotes;
|
|
||||||
import com.m2049r.xmrwallet.widget.DotBar;
|
import com.m2049r.xmrwallet.widget.DotBar;
|
||||||
import com.m2049r.xmrwallet.widget.Toolbar;
|
import com.m2049r.xmrwallet.widget.Toolbar;
|
||||||
|
|
||||||
@@ -104,6 +105,14 @@ public class SendFragment extends Fragment
|
|||||||
|
|
||||||
static private int MAX_FALLBACK = Integer.MAX_VALUE;
|
static private int MAX_FALLBACK = Integer.MAX_VALUE;
|
||||||
|
|
||||||
|
public static SendFragment newInstance(String uri) {
|
||||||
|
SendFragment f = new SendFragment();
|
||||||
|
Bundle args = new Bundle();
|
||||||
|
args.putString(WalletActivity.REQUEST_URI, uri);
|
||||||
|
f.setArguments(args);
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||||
Bundle savedInstanceState) {
|
Bundle savedInstanceState) {
|
||||||
@@ -187,6 +196,16 @@ public class SendFragment extends Fragment
|
|||||||
etDummy.requestFocus();
|
etDummy.requestFocus();
|
||||||
Helper.hideKeyboard(getActivity());
|
Helper.hideKeyboard(getActivity());
|
||||||
|
|
||||||
|
Bundle args = getArguments();
|
||||||
|
if (args != null) {
|
||||||
|
String uri = args.getString(WalletActivity.REQUEST_URI);
|
||||||
|
Timber.d("URI: %s", uri);
|
||||||
|
if (uri != null) {
|
||||||
|
barcodeData = BarcodeData.fromQrCode(uri);
|
||||||
|
Timber.d("barcodeData: %s", barcodeData != null ? barcodeData.toString() : "null");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -34,6 +34,7 @@ import java.io.IOException;
|
|||||||
import timber.log.Timber;
|
import timber.log.Timber;
|
||||||
|
|
||||||
public class Ledger {
|
public class Ledger {
|
||||||
|
static final public boolean ENABLED = false;
|
||||||
// 5:20 is same as wallet2.cpp::restore()
|
// 5:20 is same as wallet2.cpp::restore()
|
||||||
static public final int LOOKAHEAD_ACCOUNTS = 5;
|
static public final int LOOKAHEAD_ACCOUNTS = 5;
|
||||||
static public final int LOOKAHEAD_SUBADDRESSES = 20;
|
static public final int LOOKAHEAD_SUBADDRESSES = 20;
|
||||||
@@ -44,6 +45,7 @@ public class Ledger {
|
|||||||
public static final int OK[] = {SW_OK};
|
public static final int OK[] = {SW_OK};
|
||||||
|
|
||||||
public static UsbDevice findDevice(UsbManager usbManager) {
|
public static UsbDevice findDevice(UsbManager usbManager) {
|
||||||
|
if (!ENABLED) return null;
|
||||||
return BTChipTransportAndroidHID.getDevice(usbManager);
|
return BTChipTransportAndroidHID.getDevice(usbManager);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -6,7 +6,6 @@ import android.os.Looper;
|
|||||||
|
|
||||||
import com.m2049r.xmrwallet.R;
|
import com.m2049r.xmrwallet.R;
|
||||||
import com.m2049r.xmrwallet.dialog.ProgressDialog;
|
import com.m2049r.xmrwallet.dialog.ProgressDialog;
|
||||||
import com.m2049r.xmrwallet.model.WalletManager;
|
|
||||||
|
|
||||||
import timber.log.Timber;
|
import timber.log.Timber;
|
||||||
|
|
||||||
|
@@ -587,6 +587,11 @@ public class Helper {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// set FLAG_SECURE to prevent screenshots in Release Mode
|
||||||
|
if (!(BuildConfig.DEBUG && BuildConfig.FLAVOR_type.equals("alpha"))) {
|
||||||
|
openDialog.getWindow().setFlags(WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE);
|
||||||
|
}
|
||||||
|
|
||||||
Helper.showKeyboard(openDialog);
|
Helper.showKeyboard(openDialog);
|
||||||
openDialog.show();
|
openDialog.show();
|
||||||
}
|
}
|
||||||
|
@@ -244,32 +244,48 @@ public class KeyStoreHelper {
|
|||||||
Timber.d("M Keys created");
|
Timber.d("M Keys created");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static KeyStore.PrivateKeyEntry getPrivateKeyEntry(String alias) {
|
private static PrivateKey getPrivateKey(String alias) {
|
||||||
try {
|
try {
|
||||||
KeyStore ks = KeyStore
|
KeyStore ks = KeyStore
|
||||||
.getInstance(SecurityConstants.KEYSTORE_PROVIDER_ANDROID_KEYSTORE);
|
.getInstance(SecurityConstants.KEYSTORE_PROVIDER_ANDROID_KEYSTORE);
|
||||||
ks.load(null);
|
ks.load(null);
|
||||||
KeyStore.Entry entry = ks.getEntry(alias, null);
|
//KeyStore.Entry entry = ks.getEntry(alias, null);
|
||||||
|
PrivateKey privateKey = (PrivateKey) ks.getKey(alias, null);
|
||||||
|
|
||||||
if (entry == null) {
|
if (privateKey == null) {
|
||||||
Timber.w("No key found under alias: %s", alias);
|
Timber.w("No key found under alias: %s", alias);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(entry instanceof KeyStore.PrivateKeyEntry)) {
|
return privateKey;
|
||||||
Timber.w("Not an instance of a PrivateKeyEntry");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return (KeyStore.PrivateKeyEntry) entry;
|
|
||||||
} catch (IOException | NoSuchAlgorithmException | CertificateException
|
} catch (IOException | NoSuchAlgorithmException | CertificateException
|
||||||
| UnrecoverableEntryException | KeyStoreException ex) {
|
| UnrecoverableEntryException | KeyStoreException ex) {
|
||||||
throw new IllegalStateException(ex);
|
throw new IllegalStateException(ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static PublicKey getPublicKey(String alias) {
|
||||||
|
try {
|
||||||
|
KeyStore ks = KeyStore
|
||||||
|
.getInstance(SecurityConstants.KEYSTORE_PROVIDER_ANDROID_KEYSTORE);
|
||||||
|
ks.load(null);
|
||||||
|
|
||||||
|
PublicKey publicKey = ks.getCertificate(alias).getPublicKey();
|
||||||
|
|
||||||
|
if (publicKey == null) {
|
||||||
|
Timber.w("No public key");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return publicKey;
|
||||||
|
} catch (IOException | NoSuchAlgorithmException | CertificateException
|
||||||
|
| KeyStoreException ex) {
|
||||||
|
throw new IllegalStateException(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static byte[] encrypt(String alias, byte[] data) {
|
private static byte[] encrypt(String alias, byte[] data) {
|
||||||
try {
|
try {
|
||||||
PublicKey publicKey = getPrivateKeyEntry(alias).getCertificate().getPublicKey();
|
PublicKey publicKey = getPublicKey(alias);
|
||||||
Cipher cipher = Cipher.getInstance(SecurityConstants.CIPHER_RSA_ECB_PKCS1);
|
Cipher cipher = Cipher.getInstance(SecurityConstants.CIPHER_RSA_ECB_PKCS1);
|
||||||
|
|
||||||
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
|
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
|
||||||
@@ -283,9 +299,8 @@ public class KeyStoreHelper {
|
|||||||
|
|
||||||
private static byte[] decrypt(String alias, byte[] data) {
|
private static byte[] decrypt(String alias, byte[] data) {
|
||||||
try {
|
try {
|
||||||
KeyStore.PrivateKeyEntry pke = getPrivateKeyEntry(alias);
|
PrivateKey privateKey = getPrivateKey(alias);
|
||||||
if (pke == null) return null;
|
if (privateKey == null) return null;
|
||||||
PrivateKey privateKey = pke.getPrivateKey();
|
|
||||||
Cipher cipher = Cipher.getInstance(SecurityConstants.CIPHER_RSA_ECB_PKCS1);
|
Cipher cipher = Cipher.getInstance(SecurityConstants.CIPHER_RSA_ECB_PKCS1);
|
||||||
|
|
||||||
cipher.init(Cipher.DECRYPT_MODE, privateKey);
|
cipher.init(Cipher.DECRYPT_MODE, privateKey);
|
||||||
@@ -306,41 +321,14 @@ public class KeyStoreHelper {
|
|||||||
*/
|
*/
|
||||||
private static byte[] signData(String alias, byte[] data) throws NoSuchAlgorithmException,
|
private static byte[] signData(String alias, byte[] data) throws NoSuchAlgorithmException,
|
||||||
InvalidKeyException, SignatureException {
|
InvalidKeyException, SignatureException {
|
||||||
KeyStore.PrivateKeyEntry pke = getPrivateKeyEntry(alias);
|
PrivateKey privateKey = getPrivateKey(alias);
|
||||||
if (pke == null) return null;
|
if (privateKey == null) return null;
|
||||||
PrivateKey privateKey = getPrivateKeyEntry(alias).getPrivateKey();
|
|
||||||
Signature s = Signature.getInstance(SecurityConstants.SIGNATURE_SHA256withRSA);
|
Signature s = Signature.getInstance(SecurityConstants.SIGNATURE_SHA256withRSA);
|
||||||
s.initSign(privateKey);
|
s.initSign(privateKey);
|
||||||
s.update(data);
|
s.update(data);
|
||||||
return s.sign();
|
return s.sign();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Given some data and a signature, uses the key pair stored in the Android
|
|
||||||
* Key Store to verify that the data was signed by this application, using
|
|
||||||
* that key pair.
|
|
||||||
*
|
|
||||||
* @param data The data to be verified.
|
|
||||||
* @param signature The signature provided for the data.
|
|
||||||
* @return A boolean value telling you whether the signature is valid or
|
|
||||||
* not.
|
|
||||||
*/
|
|
||||||
private static boolean verifyData(String alias, byte[] data, byte[] signature)
|
|
||||||
throws NoSuchAlgorithmException, InvalidKeyException, SignatureException {
|
|
||||||
|
|
||||||
// Make sure the signature string exists
|
|
||||||
if (signature == null) {
|
|
||||||
Timber.w("Invalid signature.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
KeyStore.PrivateKeyEntry keyEntry = getPrivateKeyEntry(alias);
|
|
||||||
Signature s = Signature.getInstance(SecurityConstants.SIGNATURE_SHA256withRSA);
|
|
||||||
s.initVerify(keyEntry.getCertificate());
|
|
||||||
s.update(data);
|
|
||||||
return s.verify(signature);
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface SecurityConstants {
|
public interface SecurityConstants {
|
||||||
String KEYSTORE_PROVIDER_ANDROID_KEYSTORE = "AndroidKeyStore";
|
String KEYSTORE_PROVIDER_ANDROID_KEYSTORE = "AndroidKeyStore";
|
||||||
String TYPE_RSA = "RSA";
|
String TYPE_RSA = "RSA";
|
||||||
|
@@ -100,6 +100,7 @@ public class RestoreHeight {
|
|||||||
blockheight.put("2018-12-01", 1716687L);
|
blockheight.put("2018-12-01", 1716687L);
|
||||||
blockheight.put("2019-01-01", 1738923L);
|
blockheight.put("2019-01-01", 1738923L);
|
||||||
blockheight.put("2019-02-01", 1761435L);
|
blockheight.put("2019-02-01", 1761435L);
|
||||||
|
blockheight.put("2019-03-01", 1781681L);
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getHeight(String date) {
|
public long getHeight(String date) {
|
||||||
|
@@ -1,7 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:layout_margin="8dp">
|
android:layout_margin="8dp">
|
||||||
@@ -90,7 +89,7 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:hint="@string/generate_mnemonic_hint"
|
android:hint="@string/generate_mnemonic_hint"
|
||||||
android:imeOptions="actionNext"
|
android:imeOptions="actionNext"
|
||||||
android:inputType="textMultiLine"
|
android:inputType="textMultiLine|textVisiblePassword"
|
||||||
android:textAlignment="textStart" />
|
android:textAlignment="textStart" />
|
||||||
</android.support.design.widget.TextInputLayout>
|
</android.support.design.widget.TextInputLayout>
|
||||||
|
|
||||||
|
@@ -79,9 +79,9 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_alignParentEnd="true"
|
android:layout_alignParentEnd="true"
|
||||||
android:layout_centerInParent="true"
|
android:layout_centerInParent="true"
|
||||||
android:padding="12dp"
|
|
||||||
android:background="?android:attr/selectableItemBackgroundBorderless"
|
android:background="?android:attr/selectableItemBackgroundBorderless"
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
|
android:padding="12dp"
|
||||||
android:src="@drawable/ic_search_orange_24dp" />
|
android:src="@drawable/ic_search_orange_24dp" />
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
|
|
||||||
@@ -104,18 +104,13 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
<ScrollView
|
<ImageView
|
||||||
android:layout_width="match_parent"
|
android:id="@+id/ivGunther"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:fillViewport="true">
|
android:adjustViewBounds="true"
|
||||||
|
android:layout_gravity="center"
|
||||||
<ImageView
|
android:padding="48dp" />
|
||||||
android:id="@+id/ivGunther"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:adjustViewBounds="true"
|
|
||||||
android:padding="48dp" />
|
|
||||||
</ScrollView>
|
|
||||||
|
|
||||||
<android.support.v7.widget.RecyclerView xmlns:tools="http://schemas.android.com/tools"
|
<android.support.v7.widget.RecyclerView xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:id="@+id/list"
|
android:id="@+id/list"
|
||||||
|
11
app/src/main/res/menu/receive_menu.xml
Normal file
11
app/src/main/res/menu/receive_menu.xml
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||||
|
|
||||||
|
<item
|
||||||
|
android:id="@+id/menu_item_share"
|
||||||
|
android:title="Share"
|
||||||
|
app:actionProviderClass="android.support.v7.widget.ShareActionProvider"
|
||||||
|
app:showAsAction="ifRoom" />
|
||||||
|
|
||||||
|
</menu>
|
@@ -289,4 +289,17 @@
|
|||||||
]]></string>
|
]]></string>
|
||||||
|
|
||||||
<!-- Note for translators: new/changed text also in help_send -->
|
<!-- Note for translators: new/changed text also in help_send -->
|
||||||
|
|
||||||
|
<string name="help_uri"><![CDATA[
|
||||||
|
<h1>Using a payment link</h1>
|
||||||
|
<p>You have started monerujo with a payment link. In order to send funds, please do the following:</p>
|
||||||
|
<p>
|
||||||
|
1. Open the wallet you want to spend from<br>
|
||||||
|
2. Wait until the wallet is synced & the "Give" button appears<br>
|
||||||
|
3. Touch the "Give" button
|
||||||
|
</p>
|
||||||
|
<p>The payment details will be filled in. Check them and proceed like for any other transaction.</p>
|
||||||
|
]]></string>
|
||||||
|
|
||||||
|
<string name="help_ok">Got it!</string> <!-- Note: "Got it" as in "I understand this" -->
|
||||||
</resources>
|
</resources>
|
||||||
|
@@ -274,4 +274,17 @@
|
|||||||
]]></string>
|
]]></string>
|
||||||
|
|
||||||
<!-- Note for translators: new/changed text also in help_send -->
|
<!-- Note for translators: new/changed text also in help_send -->
|
||||||
|
|
||||||
|
<string name="help_uri"><![CDATA[
|
||||||
|
<h1>Using a payment link</h1>
|
||||||
|
<p>You have started monerujo with a payment link. In order to send funds, please do the following:</p>
|
||||||
|
<p>
|
||||||
|
1. Open the wallet you want to spend from<br>
|
||||||
|
2. Wait until the wallet is synced & the "Give" button appears<br>
|
||||||
|
3. Touch the "Give" button
|
||||||
|
</p>
|
||||||
|
<p>The payment details will be filled in. Check them and proceed like for any other transaction.</p>
|
||||||
|
]]></string>
|
||||||
|
|
||||||
|
<string name="help_ok">Got it!</string> <!-- Note: "Got it" as in "I understand this" -->
|
||||||
</resources>
|
</resources>
|
||||||
|
57
app/src/main/res/values-eo/about.xml
Normal file
57
app/src/main/res/values-eo/about.xml
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<string name="about_close">Fermi</string>
|
||||||
|
<string name="about_whoami">Mi estas monerujo</string>
|
||||||
|
<string name="about_version">Versio %1$s (%2$d)</string>
|
||||||
|
|
||||||
|
<string name="credits_text"><![CDATA[
|
||||||
|
<b>Agnoskoj</b>
|
||||||
|
<br/>
|
||||||
|
m2049r, baltsar777, anhdres, keejef,
|
||||||
|
rehrar, EarlOfEgo, ErCiccione kaj aliaj.
|
||||||
|
<br/><br/>
|
||||||
|
<a href="https://monerujo.io/">monerujo.io</a>
|
||||||
|
]]></string>
|
||||||
|
|
||||||
|
<string name="privacy_policy"><![CDATA[
|
||||||
|
<h1>Privateca politiko</h1>
|
||||||
|
<p>Tiu paĝo informas vin pri nia politiko rilate al la kolektado, uzado
|
||||||
|
kaj rivelado de personaj informoj kiujn ni ricevas de uzantoj de la
|
||||||
|
aplikaĵo. (monerujo: Monero Wallet).</p>
|
||||||
|
<p>Uzante la aplikaĵon, vi akceptas la kolektadon kaj uzon de informoj
|
||||||
|
kongrue al tiu politiko.</p>
|
||||||
|
<h2>Kolektitaj datumoj</h2>
|
||||||
|
<p>Persona datumo estas ĉiu ajn datumo kiu povas identigi personon.<p>
|
||||||
|
<p>Monero-ŝlosiloj kaj publikaj adresoj kolektiĝas kaj traktiĝas de la aplikaĵo
|
||||||
|
lokale, por la celo trakti transakciojn, kaj sendiĝas sur la Monero-reto je ĉifrita
|
||||||
|
formo.</p>
|
||||||
|
<p>Aliaj personaj datumoj ne kolektiĝas de la aplikaĵo.</p>
|
||||||
|
<p>Se vi uzas la opcian funkcionon, kiu permesas nombrumi vian pagon je alia valuto (ekz. dolaroj),
|
||||||
|
monerujo informpetos pri la kurzo per la publika interfaco de coinmarketcap.com.
|
||||||
|
Vidu ilian privatecan politikon je https://coinmarketcap.com/privacy por detaloj pri
|
||||||
|
kiel la datumo de viaj petoj kolektiĝos.</p>
|
||||||
|
<p>Se vi uzas la aplikaĵon por pagi al Bitmono-adresoj, vi uzos la XMR.TO-servon.
|
||||||
|
Vidu ilian privatecan politikon je https://xmr.to/ por detaloj. Monerujo sendos al ili la
|
||||||
|
BTC-ricevontadreson kaj kvanton. Via IP-adreso ankaŭ kolekteblos.</p>
|
||||||
|
<h2>Permesoj de la aplikaĵo</h2>
|
||||||
|
<ul>
|
||||||
|
<li>INTERRETO : Konekti kun la Monero-reto per noda demono</li>
|
||||||
|
<li>LEGI_EKSTERAJN_MEMORILOJN : Legi la monujdosierojn kiuj konserviĝas en la aparato</li>
|
||||||
|
<li>SKRIBI_EKSTERAJN_MEMORILOJN : Skribi la monujdosierojn kiuj konserviĝas en la aparato</li>
|
||||||
|
<li>LASI_VEKA : Lasi la aparaton veka dum la sinkronizado</li>
|
||||||
|
<li>FILMILO : Skani QR-kodojn por ricevi Monerojn</li>
|
||||||
|
</ul>
|
||||||
|
<h2>Ŝanĝoj de la privateca politiko</h2>
|
||||||
|
<p>Ni eble ĝisdatigos tiun privatecan politikon de temp\' al tempo. Ni
|
||||||
|
sciigos vin pri ĉiu ŝanĝo tiel : ni sendos la novan privatecan politikon en la
|
||||||
|
aplikaĵon kaj sur la retejo (www.monerujo.io)
|
||||||
|
Ni konsilas al vi, ke vi regule gvatu tiun dokumenton kaze de ŝanĝoj.
|
||||||
|
<p>Tiu privateca politiko ĝisdatiĝis lastfoje la 10an de novembro 2017.
|
||||||
|
</p>
|
||||||
|
<h2>Kontaktu nin</h2>
|
||||||
|
<p>Se vi havas ian demandon pri nia privateca politiko,
|
||||||
|
aŭ pri kiel viaj datumoj kolektiĝas kaj traktiĝas,
|
||||||
|
kontaktu retpoŝte privacy@monerujo.io.
|
||||||
|
</p>
|
||||||
|
]]></string>
|
||||||
|
</resources>
|
327
app/src/main/res/values-eo/help.xml
Normal file
327
app/src/main/res/values-eo/help.xml
Normal file
File diff suppressed because it is too large
Load Diff
378
app/src/main/res/values-eo/strings.xml
Normal file
378
app/src/main/res/values-eo/strings.xml
Normal file
File diff suppressed because it is too large
Load Diff
@@ -314,4 +314,17 @@
|
|||||||
]]></string>
|
]]></string>
|
||||||
|
|
||||||
<!-- Note for translators: new/changed text also in help_send -->
|
<!-- Note for translators: new/changed text also in help_send -->
|
||||||
|
|
||||||
|
<string name="help_uri"><![CDATA[
|
||||||
|
<h1>Using a payment link</h1>
|
||||||
|
<p>You have started monerujo with a payment link. In order to send funds, please do the following:</p>
|
||||||
|
<p>
|
||||||
|
1. Open the wallet you want to spend from<br>
|
||||||
|
2. Wait until the wallet is synced & the "Give" button appears<br>
|
||||||
|
3. Touch the "Give" button
|
||||||
|
</p>
|
||||||
|
<p>The payment details will be filled in. Check them and proceed like for any other transaction.</p>
|
||||||
|
]]></string>
|
||||||
|
|
||||||
|
<string name="help_ok">Got it!</string> <!-- Note: "Got it" as in "I understand this" -->
|
||||||
</resources>
|
</resources>
|
||||||
|
@@ -306,4 +306,17 @@
|
|||||||
]]></string>
|
]]></string>
|
||||||
|
|
||||||
<!-- Note for translators: new/changed text also in help_send -->
|
<!-- Note for translators: new/changed text also in help_send -->
|
||||||
|
|
||||||
|
<string name="help_uri"><![CDATA[
|
||||||
|
<h1>Using a payment link</h1>
|
||||||
|
<p>You have started monerujo with a payment link. In order to send funds, please do the following:</p>
|
||||||
|
<p>
|
||||||
|
1. Open the wallet you want to spend from<br>
|
||||||
|
2. Wait until the wallet is synced & the "Give" button appears<br>
|
||||||
|
3. Touch the "Give" button
|
||||||
|
</p>
|
||||||
|
<p>The payment details will be filled in. Check them and proceed like for any other transaction.</p>
|
||||||
|
]]></string>
|
||||||
|
|
||||||
|
<string name="help_ok">Got it!</string> <!-- Note: "Got it" as in "I understand this" -->
|
||||||
</resources>
|
</resources>
|
||||||
|
@@ -311,4 +311,17 @@
|
|||||||
]]></string>
|
]]></string>
|
||||||
|
|
||||||
<!-- Note for translators: new/changed text also in help_send -->
|
<!-- Note for translators: new/changed text also in help_send -->
|
||||||
|
|
||||||
|
<string name="help_uri"><![CDATA[
|
||||||
|
<h1>Using a payment link</h1>
|
||||||
|
<p>You have started monerujo with a payment link. In order to send funds, please do the following:</p>
|
||||||
|
<p>
|
||||||
|
1. Open the wallet you want to spend from<br>
|
||||||
|
2. Wait until the wallet is synced & the "Give" button appears<br>
|
||||||
|
3. Touch the "Give" button
|
||||||
|
</p>
|
||||||
|
<p>The payment details will be filled in. Check them and proceed like for any other transaction.</p>
|
||||||
|
]]></string>
|
||||||
|
|
||||||
|
<string name="help_ok">Got it!</string> <!-- Note: "Got it" as in "I understand this" -->
|
||||||
</resources>
|
</resources>
|
||||||
|
@@ -296,4 +296,17 @@
|
|||||||
]]></string>
|
]]></string>
|
||||||
|
|
||||||
<!-- Note for translators: new/changed text also in help_send -->
|
<!-- Note for translators: new/changed text also in help_send -->
|
||||||
|
|
||||||
|
<string name="help_uri"><![CDATA[
|
||||||
|
<h1>Using a payment link</h1>
|
||||||
|
<p>You have started monerujo with a payment link. In order to send funds, please do the following:</p>
|
||||||
|
<p>
|
||||||
|
1. Open the wallet you want to spend from<br>
|
||||||
|
2. Wait until the wallet is synced & the "Give" button appears<br>
|
||||||
|
3. Touch the "Give" button
|
||||||
|
</p>
|
||||||
|
<p>The payment details will be filled in. Check them and proceed like for any other transaction.</p>
|
||||||
|
]]></string>
|
||||||
|
|
||||||
|
<string name="help_ok">Got it!</string> <!-- Note: "Got it" as in "I understand this" -->
|
||||||
</resources>
|
</resources>
|
||||||
|
@@ -293,4 +293,17 @@
|
|||||||
]]></string>
|
]]></string>
|
||||||
|
|
||||||
<!-- Note for translators: new/changed text also in help_send -->
|
<!-- Note for translators: new/changed text also in help_send -->
|
||||||
|
|
||||||
|
<string name="help_uri"><![CDATA[
|
||||||
|
<h1>Using a payment link</h1>
|
||||||
|
<p>You have started monerujo with a payment link. In order to send funds, please do the following:</p>
|
||||||
|
<p>
|
||||||
|
1. Open the wallet you want to spend from<br>
|
||||||
|
2. Wait until the wallet is synced & the "Give" button appears<br>
|
||||||
|
3. Touch the "Give" button
|
||||||
|
</p>
|
||||||
|
<p>The payment details will be filled in. Check them and proceed like for any other transaction.</p>
|
||||||
|
]]></string>
|
||||||
|
|
||||||
|
<string name="help_ok">Got it!</string> <!-- Note: "Got it" as in "I understand this" -->
|
||||||
</resources>
|
</resources>
|
||||||
|
@@ -429,4 +429,17 @@
|
|||||||
]]></string>
|
]]></string>
|
||||||
|
|
||||||
<!-- Note for translators: new/changed text also in help_send -->
|
<!-- Note for translators: new/changed text also in help_send -->
|
||||||
|
|
||||||
|
<string name="help_uri"><![CDATA[
|
||||||
|
<h1>Using a payment link</h1>
|
||||||
|
<p>You have started monerujo with a payment link. In order to send funds, please do the following:</p>
|
||||||
|
<p>
|
||||||
|
1. Open the wallet you want to spend from<br>
|
||||||
|
2. Wait until the wallet is synced & the "Give" button appears<br>
|
||||||
|
3. Touch the "Give" button
|
||||||
|
</p>
|
||||||
|
<p>The payment details will be filled in. Check them and proceed like for any other transaction.</p>
|
||||||
|
]]></string>
|
||||||
|
|
||||||
|
<string name="help_ok">Got it!</string> <!-- Note: "Got it" as in "I understand this" -->
|
||||||
</resources>
|
</resources>
|
||||||
|
@@ -294,4 +294,17 @@
|
|||||||
]]></string>
|
]]></string>
|
||||||
|
|
||||||
<!-- Note for translators: new/changed text also in help_send -->
|
<!-- Note for translators: new/changed text also in help_send -->
|
||||||
|
|
||||||
|
<string name="help_uri"><![CDATA[
|
||||||
|
<h1>Using a payment link</h1>
|
||||||
|
<p>You have started monerujo with a payment link. In order to send funds, please do the following:</p>
|
||||||
|
<p>
|
||||||
|
1. Open the wallet you want to spend from<br>
|
||||||
|
2. Wait until the wallet is synced & the "Give" button appears<br>
|
||||||
|
3. Touch the "Give" button
|
||||||
|
</p>
|
||||||
|
<p>The payment details will be filled in. Check them and proceed like for any other transaction.</p>
|
||||||
|
]]></string>
|
||||||
|
|
||||||
|
<string name="help_ok">Got it!</string> <!-- Note: "Got it" as in "I understand this" -->
|
||||||
</resources>
|
</resources>
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user