mirror of
https://github.com/m2049r/xmrwallet
synced 2025-09-08 20:40:51 +02:00
Compare commits
14 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
e8b749af3b | ||
![]() |
f282f01edd | ||
![]() |
f16afdbb19 | ||
![]() |
ccacec9d0b | ||
![]() |
9ebacb8528 | ||
![]() |
49a9f84226 | ||
![]() |
91b4aaad60 | ||
![]() |
c4ce12ceff | ||
![]() |
96cf9ee95e | ||
![]() |
00852da9f7 | ||
![]() |
15b90e7ebc | ||
![]() |
e270b277a5 | ||
![]() |
2842a4042f | ||
![]() |
1614c0ab84 |
1
.idea/.gitignore
generated
vendored
1
.idea/.gitignore
generated
vendored
@@ -1,2 +1,3 @@
|
|||||||
workspace.xml
|
workspace.xml
|
||||||
markdown-*
|
markdown-*
|
||||||
|
misc.xml
|
||||||
|
46
.idea/misc.xml
generated
46
.idea/misc.xml
generated
@@ -1,46 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="EntryPointsManager">
|
|
||||||
<entry_points version="2.0" />
|
|
||||||
</component>
|
|
||||||
<component name="NullableNotNullManager">
|
|
||||||
<option name="myDefaultNullable" value="android.support.annotation.Nullable" />
|
|
||||||
<option name="myDefaultNotNull" value="android.support.annotation.NonNull" />
|
|
||||||
<option name="myNullables">
|
|
||||||
<value>
|
|
||||||
<list size="4">
|
|
||||||
<item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.Nullable" />
|
|
||||||
<item index="1" class="java.lang.String" itemvalue="javax.annotation.Nullable" />
|
|
||||||
<item index="2" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.Nullable" />
|
|
||||||
<item index="3" class="java.lang.String" itemvalue="android.support.annotation.Nullable" />
|
|
||||||
</list>
|
|
||||||
</value>
|
|
||||||
</option>
|
|
||||||
<option name="myNotNulls">
|
|
||||||
<value>
|
|
||||||
<list size="4">
|
|
||||||
<item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.NotNull" />
|
|
||||||
<item index="1" class="java.lang.String" itemvalue="javax.annotation.Nonnull" />
|
|
||||||
<item index="2" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.NonNull" />
|
|
||||||
<item index="3" class="java.lang.String" itemvalue="android.support.annotation.NonNull" />
|
|
||||||
</list>
|
|
||||||
</value>
|
|
||||||
</option>
|
|
||||||
</component>
|
|
||||||
<component name="ProjectLevelVcsManager" settingsEditedManually="false">
|
|
||||||
<OptionsSetting value="true" id="Add" />
|
|
||||||
<OptionsSetting value="true" id="Remove" />
|
|
||||||
<OptionsSetting value="true" id="Checkout" />
|
|
||||||
<OptionsSetting value="true" id="Update" />
|
|
||||||
<OptionsSetting value="true" id="Status" />
|
|
||||||
<OptionsSetting value="true" id="Edit" />
|
|
||||||
<ConfirmationsSetting value="0" id="Add" />
|
|
||||||
<ConfirmationsSetting value="0" id="Remove" />
|
|
||||||
</component>
|
|
||||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_7" default="true" assert-keyword="true" jdk-15="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
|
|
||||||
<output url="file://$PROJECT_DIR$/build/classes" />
|
|
||||||
</component>
|
|
||||||
<component name="ProjectType">
|
|
||||||
<option name="id" value="Android" />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
@@ -14,7 +14,7 @@ You may lose all your Moneroj if you use this App. Be cautious when spending on
|
|||||||
- Based off monero v0.11.0.0 with PR #2289 applied
|
- Based off monero v0.11.0.0 with PR #2289 applied
|
||||||
- currently only android32 (runs on 64-bit as well)
|
- currently only android32 (runs on 64-bit as well)
|
||||||
- works on the testnet & mainnet
|
- works on the testnet & mainnet
|
||||||
- takes forever to sync due to 32-bit architecture
|
- sync is slow due to 32-bit architecture
|
||||||
- use your own daemon - it's easy
|
- use your own daemon - it's easy
|
||||||
- screen stays on until first sync is complete
|
- screen stays on until first sync is complete
|
||||||
- saves wallet only on first sync and when sending transactions or editing notes
|
- saves wallet only on first sync and when sending transactions or editing notes
|
||||||
@@ -25,11 +25,13 @@ You may lose all your Moneroj if you use this App. Be cautious when spending on
|
|||||||
- more sensible error dialogs
|
- more sensible error dialogs
|
||||||
|
|
||||||
### Issues / Pitfalls
|
### Issues / Pitfalls
|
||||||
|
- The backups folder is now called "backups" and not ".backups" - which in most file explorers was a hidden folder
|
||||||
|
- Wallets are now created directly in the "monerujo" folder, and not in the ".new" folder as before
|
||||||
|
- You may want to check the old folders with a file browsing app and delete the ".new" and ".backups" folders AFTER moving neccessary wallet files to the new locations. Or simply make new backups from within Monerujo.
|
||||||
|
- Also note, that on some devices the backups will only be visible on a PC over USB after a reboot of the device (it's an Android bug/feature)
|
||||||
- Created wallets on a private testnet are unusable because the restore height is set to that
|
- Created wallets on a private testnet are unusable because the restore height is set to that
|
||||||
of the "real" testnet. After creating a new wallet, make a **new** one by recovering from the seed.
|
of the "real" testnet. After creating a new wallet, make a **new** one by recovering from the seed.
|
||||||
The official monero client shows the same behaviour.
|
The official monero client shows the same behaviour.
|
||||||
- In rare occasions the monero core code returns a wallet address with corrupted characters -
|
|
||||||
in these cases Monerujo crashes on purpose to make sure nothing bad happens
|
|
||||||
|
|
||||||
### HOW TO BUILD
|
### HOW TO BUILD
|
||||||
No need to build. Binaries are included:
|
No need to build. Binaries are included:
|
||||||
|
@@ -8,8 +8,8 @@ android {
|
|||||||
applicationId "com.m2049r.xmrwallet"
|
applicationId "com.m2049r.xmrwallet"
|
||||||
minSdkVersion 21
|
minSdkVersion 21
|
||||||
targetSdkVersion 25
|
targetSdkVersion 25
|
||||||
versionCode 20
|
versionCode 25
|
||||||
versionName "0.8.0.7"
|
versionName "1.0.2"
|
||||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||||
externalNativeBuild {
|
externalNativeBuild {
|
||||||
cmake {
|
cmake {
|
||||||
|
@@ -3,7 +3,6 @@
|
|||||||
package="com.m2049r.xmrwallet">
|
package="com.m2049r.xmrwallet">
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
|
||||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||||
|
Binary file not shown.
Before Width: | Height: | Size: 253 KiB |
@@ -18,6 +18,7 @@ package com.m2049r.xmrwallet;
|
|||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
import android.support.v4.app.Fragment;
|
import android.support.v4.app.Fragment;
|
||||||
import android.text.Editable;
|
import android.text.Editable;
|
||||||
import android.text.InputType;
|
import android.text.InputType;
|
||||||
@@ -25,6 +26,8 @@ import android.text.TextWatcher;
|
|||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
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.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.view.inputmethod.EditorInfo;
|
import android.view.inputmethod.EditorInfo;
|
||||||
@@ -379,4 +382,15 @@ public class GenerateFragment extends Fragment {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
setHasOptionsMenu(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
||||||
|
inflater.inflate(R.menu.create_wallet_menu, menu);
|
||||||
|
super.onCreateOptionsMenu(menu, inflater);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -19,14 +19,18 @@ package com.m2049r.xmrwallet;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.os.AsyncTask;
|
import android.os.AsyncTask;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
import android.support.v4.app.Fragment;
|
import android.support.v4.app.Fragment;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.Menu;
|
||||||
|
import android.view.MenuInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
import android.widget.ProgressBar;
|
import android.widget.ProgressBar;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
import com.m2049r.xmrwallet.model.Wallet;
|
import com.m2049r.xmrwallet.model.Wallet;
|
||||||
import com.m2049r.xmrwallet.model.WalletManager;
|
import com.m2049r.xmrwallet.model.WalletManager;
|
||||||
@@ -66,6 +70,20 @@ public class GenerateReviewFragment extends Fragment {
|
|||||||
boolean testnet = WalletManager.getInstance().isTestNet();
|
boolean testnet = WalletManager.getInstance().isTestNet();
|
||||||
tvWalletMnemonic.setTextIsSelectable(testnet);
|
tvWalletMnemonic.setTextIsSelectable(testnet);
|
||||||
tvWalletSpendKey.setTextIsSelectable(testnet);
|
tvWalletSpendKey.setTextIsSelectable(testnet);
|
||||||
|
if (!testnet) {
|
||||||
|
tvWalletMnemonic.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
Toast.makeText(getActivity(), getString(R.string.message_noselect_seed), Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
tvWalletSpendKey.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
Toast.makeText(getActivity(), getString(R.string.message_noselect_key), Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
bAccept.setOnClickListener(new View.OnClickListener() {
|
bAccept.setOnClickListener(new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
@@ -199,4 +217,15 @@ public class GenerateReviewFragment extends Fragment {
|
|||||||
boolean backOk() {
|
boolean backOk() {
|
||||||
return !type.equals(GenerateReviewFragment.VIEW_TYPE_ACCEPT);
|
return !type.equals(GenerateReviewFragment.VIEW_TYPE_ACCEPT);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
@Override
|
||||||
|
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
setHasOptionsMenu(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
||||||
|
inflater.inflate(R.menu.wallet_details_menu, menu);
|
||||||
|
}
|
||||||
|
}
|
@@ -24,6 +24,7 @@ import android.content.DialogInterface;
|
|||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
|
import android.media.MediaScannerConnection;
|
||||||
import android.os.AsyncTask;
|
import android.os.AsyncTask;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.StrictMode;
|
import android.os.StrictMode;
|
||||||
@@ -44,15 +45,14 @@ import android.widget.EditText;
|
|||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import com.m2049r.xmrwallet.layout.DropDownEditText;
|
import com.m2049r.xmrwallet.dialog.HelpFragment;
|
||||||
import com.m2049r.xmrwallet.license.LicensesFragment;
|
import com.m2049r.xmrwallet.dialog.LicensesFragment;
|
||||||
import com.m2049r.xmrwallet.model.Wallet;
|
import com.m2049r.xmrwallet.model.Wallet;
|
||||||
import com.m2049r.xmrwallet.model.WalletManager;
|
import com.m2049r.xmrwallet.model.WalletManager;
|
||||||
import com.m2049r.xmrwallet.service.WalletService;
|
import com.m2049r.xmrwallet.service.WalletService;
|
||||||
import com.m2049r.xmrwallet.util.AsyncExchangeRate;
|
import com.m2049r.xmrwallet.util.AsyncExchangeRate;
|
||||||
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.util.NodeList;
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
@@ -308,12 +308,14 @@ public class LoginActivity extends AppCompatActivity
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean backupWallet(String walletName) {
|
private boolean backupWallet(String walletName) {
|
||||||
File backupFolder = new File(getStorageRoot(), ".backups");
|
File backupFolder = new File(getStorageRoot(), "backups");
|
||||||
if (!backupFolder.exists()) {
|
if (!backupFolder.exists()) {
|
||||||
if (!backupFolder.mkdir()) {
|
if (!backupFolder.mkdir()) {
|
||||||
Log.e(TAG, "Cannot create backup dir " + backupFolder.getAbsolutePath());
|
Log.e(TAG, "Cannot create backup dir " + backupFolder.getAbsolutePath());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
// make folder visible over USB/MTP
|
||||||
|
MediaScannerConnection.scanFile(this, new String[]{backupFolder.toString()}, null, null);
|
||||||
}
|
}
|
||||||
File walletFile = Helper.getWalletFile(LoginActivity.this, walletName);
|
File walletFile = Helper.getWalletFile(LoginActivity.this, walletName);
|
||||||
File backupFile = new File(backupFolder, walletName);
|
File backupFile = new File(backupFolder, walletName);
|
||||||
@@ -726,26 +728,17 @@ public class LoginActivity extends AppCompatActivity
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Boolean doInBackground(Void... params) {
|
protected Boolean doInBackground(Void... params) {
|
||||||
File newWalletFolder = new File(getStorageRoot(), ".new");
|
File newWalletFolder = getStorageRoot();
|
||||||
if (!newWalletFolder.exists()) {
|
|
||||||
if (!newWalletFolder.mkdir()) {
|
|
||||||
Log.e(TAG, "Cannot create new wallet dir " + newWalletFolder.getAbsolutePath());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!newWalletFolder.isDirectory()) {
|
if (!newWalletFolder.isDirectory()) {
|
||||||
Log.e(TAG, "New wallet dir " + newWalletFolder.getAbsolutePath() + "is not a directory");
|
Log.e(TAG, "Wallet dir " + newWalletFolder.getAbsolutePath() + "is not a directory");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
File cacheFile = new File(newWalletFolder, walletName);
|
File cacheFile = new File(newWalletFolder, walletName);
|
||||||
cacheFile.delete();
|
|
||||||
File keysFile = new File(newWalletFolder, walletName + ".keys");
|
File keysFile = new File(newWalletFolder, walletName + ".keys");
|
||||||
keysFile.delete();
|
|
||||||
File addressFile = new File(newWalletFolder, walletName + ".address.txt");
|
File addressFile = new File(newWalletFolder, walletName + ".address.txt");
|
||||||
addressFile.delete();
|
|
||||||
|
|
||||||
if (cacheFile.exists() || keysFile.exists() || addressFile.exists()) {
|
if (cacheFile.exists() || keysFile.exists() || addressFile.exists()) {
|
||||||
Log.e(TAG, "Cannot remove all old wallet files: " + cacheFile.getAbsolutePath());
|
Log.e(TAG, "Some wallet files already exist for " + cacheFile.getAbsolutePath());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -854,15 +847,11 @@ public class LoginActivity extends AppCompatActivity
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onAccept(final String name, final String password) {
|
public void onAccept(final String name, final String password) {
|
||||||
File newWalletFile = new File(new File(getStorageRoot(), ".new"), name);
|
|
||||||
File walletFolder = getStorageRoot();
|
File walletFolder = getStorageRoot();
|
||||||
File walletFile = new File(walletFolder, name);
|
File walletFile = new File(walletFolder, name);
|
||||||
boolean rc = copyWallet(newWalletFile, walletFile, false);
|
walletFile.delete(); // when recovering wallets, the cache seems corrupt
|
||||||
if (rc) {
|
// TODO: figure out why this is so? Only for a private testnet?
|
||||||
walletFile.delete(); // when recovering wallets, the cache seems corrupt
|
boolean rc = testWallet(walletFile.getAbsolutePath(), password) == Wallet.Status.Status_Ok;
|
||||||
// TODO: figure out why this is so? Only for a private testnet?
|
|
||||||
rc = testWallet(walletFile.getAbsolutePath(), password) == Wallet.Status.Status_Ok;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rc) {
|
if (rc) {
|
||||||
popFragmentStack(GENERATE_STACK);
|
popFragmentStack(GENERATE_STACK);
|
||||||
@@ -871,7 +860,7 @@ public class LoginActivity extends AppCompatActivity
|
|||||||
} else {
|
} else {
|
||||||
Log.e(TAG, "Wallet store failed to " + walletFile.getAbsolutePath());
|
Log.e(TAG, "Wallet store failed to " + walletFile.getAbsolutePath());
|
||||||
Toast.makeText(LoginActivity.this,
|
Toast.makeText(LoginActivity.this,
|
||||||
getString(R.string.generate_wallet_create_failed_2), Toast.LENGTH_LONG).show();
|
getString(R.string.generate_wallet_create_failed), Toast.LENGTH_LONG).show();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -981,6 +970,12 @@ public class LoginActivity extends AppCompatActivity
|
|||||||
@Override
|
@Override
|
||||||
public boolean onOptionsItemSelected(MenuItem item) {
|
public boolean onOptionsItemSelected(MenuItem item) {
|
||||||
switch (item.getItemId()) {
|
switch (item.getItemId()) {
|
||||||
|
case R.id.action_create_help:
|
||||||
|
HelpFragment.displayHelp(getSupportFragmentManager(),R.raw.help_create);
|
||||||
|
return true;
|
||||||
|
case R.id.action_details_help:
|
||||||
|
HelpFragment.displayHelp(getSupportFragmentManager(),R.raw.help_details);
|
||||||
|
return true;
|
||||||
case R.id.action_lincense_info:
|
case R.id.action_lincense_info:
|
||||||
LicensesFragment.displayLicensesFragment(getSupportFragmentManager());
|
LicensesFragment.displayLicensesFragment(getSupportFragmentManager());
|
||||||
return true;
|
return true;
|
||||||
|
@@ -151,7 +151,10 @@ public class WalletActivity extends AppCompatActivity implements WalletFragment.
|
|||||||
Log.d(TAG, "onCreate()");
|
Log.d(TAG, "onCreate()");
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
if (savedInstanceState != null) {
|
if (savedInstanceState != null) {
|
||||||
// we don't store anything ourselves
|
// activity restarted
|
||||||
|
// we don't want that - finish it and fall back to previous activity
|
||||||
|
finish();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
setContentView(R.layout.wallet_activity);
|
setContentView(R.layout.wallet_activity);
|
||||||
|
@@ -186,6 +186,7 @@ public class WalletFragment extends Fragment implements TransactionInfoAdapter.O
|
|||||||
private String walletTitle = null;
|
private String walletTitle = null;
|
||||||
|
|
||||||
private void updateStatus(Wallet wallet) {
|
private void updateStatus(Wallet wallet) {
|
||||||
|
if (!isAdded()) return;
|
||||||
Log.d(TAG, "updateStatus()");
|
Log.d(TAG, "updateStatus()");
|
||||||
if (walletTitle == null) {
|
if (walletTitle == null) {
|
||||||
walletTitle = setActivityTitle(wallet);
|
walletTitle = setActivityTitle(wallet);
|
||||||
|
160
app/src/main/java/com/m2049r/xmrwallet/dialog/HelpFragment.java
Normal file
160
app/src/main/java/com/m2049r/xmrwallet/dialog/HelpFragment.java
Normal file
@@ -0,0 +1,160 @@
|
|||||||
|
/**
|
||||||
|
* Copyright 2013 Adam Speakman, m2049r
|
||||||
|
* <p>
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* <p>
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* <p>
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.m2049r.xmrwallet.dialog;
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint;
|
||||||
|
import android.app.AlertDialog;
|
||||||
|
import android.app.Dialog;
|
||||||
|
import android.content.DialogInterface;
|
||||||
|
import android.os.AsyncTask;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.support.v4.app.DialogFragment;
|
||||||
|
import android.support.v4.app.Fragment;
|
||||||
|
import android.support.v4.app.FragmentManager;
|
||||||
|
import android.support.v4.app.FragmentTransaction;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.webkit.WebView;
|
||||||
|
import android.widget.ProgressBar;
|
||||||
|
|
||||||
|
import com.m2049r.xmrwallet.R;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Based on LicensesFragment by Adam Speakman on 24/09/13.
|
||||||
|
* http://speakman.net.nz
|
||||||
|
*/
|
||||||
|
public class HelpFragment extends DialogFragment {
|
||||||
|
private static final String FRAGMENT_TAG = "com.m2049r.xmrwallet.dialog.HelpFragment";
|
||||||
|
private static final String HELP_ID = "HELP_ID";
|
||||||
|
|
||||||
|
private AsyncTask<Void, Void, String> loader;
|
||||||
|
|
||||||
|
public static HelpFragment newInstance(int helpResourceId) {
|
||||||
|
HelpFragment fragment = new HelpFragment();
|
||||||
|
|
||||||
|
Bundle bundle = new Bundle();
|
||||||
|
bundle.putInt(HELP_ID, helpResourceId);
|
||||||
|
fragment.setArguments(bundle);
|
||||||
|
|
||||||
|
return fragment;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param fm A fragment manager instance used to display this LicensesFragment.
|
||||||
|
*/
|
||||||
|
public static void displayHelp(FragmentManager fm, int helpResourceId) {
|
||||||
|
FragmentTransaction ft = fm.beginTransaction();
|
||||||
|
Fragment prev = fm.findFragmentByTag(FRAGMENT_TAG);
|
||||||
|
if (prev != null) {
|
||||||
|
ft.remove(prev);
|
||||||
|
}
|
||||||
|
ft.addToBackStack(null);
|
||||||
|
|
||||||
|
// Create and show the dialog.
|
||||||
|
DialogFragment newFragment = HelpFragment.newInstance(helpResourceId);
|
||||||
|
newFragment.show(ft, FRAGMENT_TAG);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onActivityCreated(Bundle savedInstanceState) {
|
||||||
|
super.onActivityCreated(savedInstanceState);
|
||||||
|
int helpId = 0;
|
||||||
|
Bundle arguments = getArguments();
|
||||||
|
if (arguments != null) {
|
||||||
|
helpId = arguments.getInt(HELP_ID);
|
||||||
|
}
|
||||||
|
if (helpId > 0)
|
||||||
|
loadHelp(helpId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDestroy() {
|
||||||
|
super.onDestroy();
|
||||||
|
if (loader != null) {
|
||||||
|
loader.cancel(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private WebView webView;
|
||||||
|
private ProgressBar progress;
|
||||||
|
|
||||||
|
@SuppressLint("InflateParams")
|
||||||
|
@Override
|
||||||
|
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||||
|
View content = LayoutInflater.from(getActivity()).inflate(R.layout.help_fragment, null);
|
||||||
|
webView = (WebView) content.findViewById(R.id.helpFragmentWebView);
|
||||||
|
progress = (ProgressBar) content.findViewById(R.id.helpFragmentProgress);
|
||||||
|
|
||||||
|
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
|
||||||
|
|
||||||
|
builder.setView(content);
|
||||||
|
builder.setNegativeButton(R.string.about_close,
|
||||||
|
new DialogInterface.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(DialogInterface dialog, int id) {
|
||||||
|
dialog.dismiss();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return builder.create();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void loadHelp(final int helpResourceId) {
|
||||||
|
// Load asynchronously in case of a very large file.
|
||||||
|
loader = new AsyncTask<Void, Void, String>() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String doInBackground(Void... params) {
|
||||||
|
InputStream rawResource = getActivity().getResources().openRawResource(helpResourceId);
|
||||||
|
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(rawResource));
|
||||||
|
|
||||||
|
String line;
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
|
||||||
|
try {
|
||||||
|
while ((line = bufferedReader.readLine()) != null) {
|
||||||
|
sb.append(line);
|
||||||
|
sb.append("\n");
|
||||||
|
}
|
||||||
|
bufferedReader.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
// TODO You may want to include some logging here.
|
||||||
|
}
|
||||||
|
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPostExecute(String licensesBody) {
|
||||||
|
super.onPostExecute(licensesBody);
|
||||||
|
if (getActivity() == null || isCancelled()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
progress.setVisibility(View.INVISIBLE);
|
||||||
|
webView.setVisibility(View.VISIBLE);
|
||||||
|
webView.loadDataWithBaseURL(null, licensesBody, "text/html", "utf-8", null);
|
||||||
|
loader = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}.execute();
|
||||||
|
}
|
||||||
|
}
|
@@ -14,7 +14,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.m2049r.xmrwallet.license;
|
package com.m2049r.xmrwallet.dialog;
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@@ -51,8 +51,7 @@ public class LicensesFragment extends DialogFragment {
|
|||||||
|
|
||||||
private AsyncTask<Void, Void, String> mLicenseLoader;
|
private AsyncTask<Void, Void, String> mLicenseLoader;
|
||||||
|
|
||||||
private static final String FRAGMENT_TAG = "nz.net.speakman.androidlicensespage.LicensesFragment";
|
private static final String FRAGMENT_TAG = "com.m2049r.xmrwalelt.dialog.LicensesFragment";
|
||||||
private static final String KEY_SHOW_CLOSE_BUTTON = "keyShowCloseButton";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new instance of LicensesFragment with no Close button.
|
* Creates a new instance of LicensesFragment with no Close button.
|
||||||
@@ -63,22 +62,6 @@ public class LicensesFragment extends DialogFragment {
|
|||||||
return new LicensesFragment();
|
return new LicensesFragment();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new instance of LicensesFragment with an optional Close button.
|
|
||||||
*
|
|
||||||
* @param showCloseButton Whether to show a Close button at the bottom of the dialog.
|
|
||||||
* @return A new licenses fragment.
|
|
||||||
*/
|
|
||||||
public static LicensesFragment newInstance(boolean showCloseButton) {
|
|
||||||
LicensesFragment fragment = new LicensesFragment();
|
|
||||||
|
|
||||||
Bundle bundle = new Bundle();
|
|
||||||
bundle.putBoolean(KEY_SHOW_CLOSE_BUTTON, showCloseButton);
|
|
||||||
fragment.setArguments(bundle);
|
|
||||||
|
|
||||||
return fragment;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Builds and displays a licenses fragment with no Close button. Requires
|
* Builds and displays a licenses fragment with no Close button. Requires
|
||||||
* "/res/raw/licenses.html" and "/res/layout/licenses_fragment.xml" to be
|
* "/res/raw/licenses.html" and "/res/layout/licenses_fragment.xml" to be
|
||||||
@@ -99,27 +82,6 @@ public class LicensesFragment extends DialogFragment {
|
|||||||
newFragment.show(ft, FRAGMENT_TAG);
|
newFragment.show(ft, FRAGMENT_TAG);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Builds and displays a licenses fragment with or without a Close button.
|
|
||||||
* Requires "/res/raw/licenses.html" and "/res/layout/licenses_fragment.xml"
|
|
||||||
* to be present.
|
|
||||||
*
|
|
||||||
* @param fm A fragment manager instance used to display this LicensesFragment.
|
|
||||||
* @param showCloseButton Whether to show a Close button at the bottom of the dialog.
|
|
||||||
*/
|
|
||||||
public static void displayLicensesFragment(FragmentManager fm, boolean showCloseButton) {
|
|
||||||
FragmentTransaction ft = fm.beginTransaction();
|
|
||||||
Fragment prev = fm.findFragmentByTag(FRAGMENT_TAG);
|
|
||||||
if (prev != null) {
|
|
||||||
ft.remove(prev);
|
|
||||||
}
|
|
||||||
ft.addToBackStack(null);
|
|
||||||
|
|
||||||
// Create and show the dialog.
|
|
||||||
DialogFragment newFragment = LicensesFragment.newInstance(showCloseButton);
|
|
||||||
newFragment.show(ft, FRAGMENT_TAG);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onActivityCreated(Bundle savedInstanceState) {
|
public void onActivityCreated(Bundle savedInstanceState) {
|
||||||
super.onActivityCreated(savedInstanceState);
|
super.onActivityCreated(savedInstanceState);
|
||||||
@@ -144,26 +106,18 @@ public class LicensesFragment extends DialogFragment {
|
|||||||
mWebView = (WebView) content.findViewById(R.id.licensesFragmentWebView);
|
mWebView = (WebView) content.findViewById(R.id.licensesFragmentWebView);
|
||||||
mIndeterminateProgress = (ProgressBar) content.findViewById(R.id.licensesFragmentIndeterminateProgress);
|
mIndeterminateProgress = (ProgressBar) content.findViewById(R.id.licensesFragmentIndeterminateProgress);
|
||||||
|
|
||||||
boolean showCloseButton = true;
|
|
||||||
Bundle arguments = getArguments();
|
|
||||||
if (arguments != null) {
|
|
||||||
showCloseButton = arguments.getBoolean(KEY_SHOW_CLOSE_BUTTON);
|
|
||||||
}
|
|
||||||
|
|
||||||
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
|
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
|
||||||
TextView text = (TextView) content.findViewById(R.id.text);
|
TextView text = (TextView) content.findViewById(R.id.licensesFragmentText);
|
||||||
text.setText(getString(R.string.about_text, versionName, versionCode));
|
text.setText(getString(R.string.about_text, versionName, versionCode));
|
||||||
|
|
||||||
builder.setView(content);
|
builder.setView(content);
|
||||||
if (showCloseButton) {
|
builder.setNegativeButton(R.string.about_close,
|
||||||
builder.setNegativeButton(R.string.about_close,
|
new DialogInterface.OnClickListener() {
|
||||||
new DialogInterface.OnClickListener() {
|
@Override
|
||||||
@Override
|
public void onClick(DialogInterface dialog, int id) {
|
||||||
public void onClick(DialogInterface dialog, int id) {
|
dialog.dismiss();
|
||||||
dialog.dismiss();
|
}
|
||||||
}
|
});
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return builder.create();
|
return builder.create();
|
||||||
}
|
}
|
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package com.m2049r.xmrwallet.model;
|
package com.m2049r.xmrwallet.model;
|
||||||
|
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
@@ -45,36 +46,36 @@ public class WalletManager {
|
|||||||
return WalletManager.Instance;
|
return WalletManager.Instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
private WalletManager() {
|
//private Map<String, Wallet> managedWallets;
|
||||||
this.managedWallets = new HashMap<>();
|
private Wallet managedWallet = null;
|
||||||
|
|
||||||
|
public Wallet getWallet() {
|
||||||
|
return managedWallet;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Map<String, Wallet> managedWallets;
|
private void manageWallet(Wallet wallet) {
|
||||||
|
Log.d(TAG, "Managing " + wallet.getName());
|
||||||
public Wallet getWallet(String walletId) {
|
managedWallet = wallet;
|
||||||
return managedWallets.get(walletId);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void manageWallet(String walletId, Wallet wallet) {
|
private void unmanageWallet(Wallet wallet) {
|
||||||
if (getWallet(walletId) != null) {
|
if (wallet == null) {
|
||||||
throw new IllegalStateException(walletId + " already under management!");
|
throw new IllegalArgumentException("Cannot unmanage null!");
|
||||||
}
|
}
|
||||||
Log.d(TAG, "Managing " + walletId);
|
if (getWallet() == null) {
|
||||||
managedWallets.put(walletId, wallet);
|
throw new IllegalStateException("No wallet under management!");
|
||||||
}
|
|
||||||
|
|
||||||
private void unmanageWallet(String walletId) {
|
|
||||||
if (getWallet(walletId) == null) {
|
|
||||||
throw new IllegalStateException(walletId + " not under management!");
|
|
||||||
}
|
}
|
||||||
Log.d(TAG, "Unmanaging " + walletId);
|
if (getWallet() != wallet) {
|
||||||
managedWallets.remove(walletId);
|
throw new IllegalStateException(wallet.getName() + " not under management!");
|
||||||
|
}
|
||||||
|
Log.d(TAG, "Unmanaging " + managedWallet.getName());
|
||||||
|
managedWallet = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Wallet createWallet(File aFile, String password, String language) {
|
public Wallet createWallet(File aFile, String password, String language) {
|
||||||
long walletHandle = createWalletJ(aFile.getAbsolutePath(), password, language, isTestNet());
|
long walletHandle = createWalletJ(aFile.getAbsolutePath(), password, language, isTestNet());
|
||||||
Wallet wallet = new Wallet(walletHandle);
|
Wallet wallet = new Wallet(walletHandle);
|
||||||
manageWallet(wallet.getName(), wallet);
|
manageWallet(wallet);
|
||||||
return wallet;
|
return wallet;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -83,7 +84,7 @@ public class WalletManager {
|
|||||||
public Wallet openWallet(String path, String password) {
|
public Wallet openWallet(String path, String password) {
|
||||||
long walletHandle = openWalletJ(path, password, isTestNet());
|
long walletHandle = openWalletJ(path, password, isTestNet());
|
||||||
Wallet wallet = new Wallet(walletHandle);
|
Wallet wallet = new Wallet(walletHandle);
|
||||||
manageWallet(wallet.getName(), wallet);
|
manageWallet(wallet);
|
||||||
return wallet;
|
return wallet;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -91,14 +92,14 @@ public class WalletManager {
|
|||||||
|
|
||||||
public Wallet recoveryWallet(File aFile, String mnemonic) {
|
public Wallet recoveryWallet(File aFile, String mnemonic) {
|
||||||
Wallet wallet = recoveryWallet(aFile, mnemonic, 0);
|
Wallet wallet = recoveryWallet(aFile, mnemonic, 0);
|
||||||
manageWallet(wallet.getName(), wallet);
|
manageWallet(wallet);
|
||||||
return wallet;
|
return wallet;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Wallet recoveryWallet(File aFile, String mnemonic, long restoreHeight) {
|
public Wallet recoveryWallet(File aFile, String mnemonic, long restoreHeight) {
|
||||||
long walletHandle = recoveryWalletJ(aFile.getAbsolutePath(), mnemonic, isTestNet(), restoreHeight);
|
long walletHandle = recoveryWalletJ(aFile.getAbsolutePath(), mnemonic, isTestNet(), restoreHeight);
|
||||||
Wallet wallet = new Wallet(walletHandle);
|
Wallet wallet = new Wallet(walletHandle);
|
||||||
manageWallet(wallet.getName(), wallet);
|
manageWallet(wallet);
|
||||||
return wallet;
|
return wallet;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -109,7 +110,7 @@ public class WalletManager {
|
|||||||
long walletHandle = createWalletFromKeysJ(aFile.getAbsolutePath(), language, isTestNet(), restoreHeight,
|
long walletHandle = createWalletFromKeysJ(aFile.getAbsolutePath(), language, isTestNet(), restoreHeight,
|
||||||
addressString, viewKeyString, spendKeyString);
|
addressString, viewKeyString, spendKeyString);
|
||||||
Wallet wallet = new Wallet(walletHandle);
|
Wallet wallet = new Wallet(walletHandle);
|
||||||
manageWallet(wallet.getName(), wallet);
|
manageWallet(wallet);
|
||||||
return wallet;
|
return wallet;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -123,13 +124,12 @@ public class WalletManager {
|
|||||||
public native boolean closeJ(Wallet wallet);
|
public native boolean closeJ(Wallet wallet);
|
||||||
|
|
||||||
public boolean close(Wallet wallet) {
|
public boolean close(Wallet wallet) {
|
||||||
String walletId = new File(wallet.getFilename()).getName();
|
unmanageWallet(wallet);
|
||||||
unmanageWallet(walletId);
|
|
||||||
boolean closed = closeJ(wallet);
|
boolean closed = closeJ(wallet);
|
||||||
if (!closed) {
|
if (!closed) {
|
||||||
// in case we could not close it
|
// in case we could not close it
|
||||||
// we unmanage it
|
// we manage it again
|
||||||
manageWallet(walletId, wallet);
|
manageWallet(wallet);
|
||||||
}
|
}
|
||||||
return closed;
|
return closed;
|
||||||
}
|
}
|
||||||
|
@@ -70,20 +70,11 @@ public class WalletService extends Service {
|
|||||||
private MyWalletListener listener = null;
|
private MyWalletListener listener = null;
|
||||||
|
|
||||||
private class MyWalletListener implements WalletListener {
|
private class MyWalletListener implements WalletListener {
|
||||||
private Wallet wallet;
|
|
||||||
boolean updated = true;
|
boolean updated = true;
|
||||||
|
|
||||||
Wallet getWallet() {
|
|
||||||
return wallet;
|
|
||||||
}
|
|
||||||
|
|
||||||
MyWalletListener(Wallet aWallet) {
|
|
||||||
if (aWallet == null) throw new IllegalArgumentException("Cannot open wallet!");
|
|
||||||
this.wallet = aWallet;
|
|
||||||
}
|
|
||||||
|
|
||||||
void start() {
|
void start() {
|
||||||
Log.d(TAG, "MyWalletListener.start()");
|
Log.d(TAG, "MyWalletListener.start()");
|
||||||
|
Wallet wallet = getWallet();
|
||||||
if (wallet == null) throw new IllegalStateException("No wallet!");
|
if (wallet == null) throw new IllegalStateException("No wallet!");
|
||||||
//acquireWakeLock();
|
//acquireWakeLock();
|
||||||
wallet.setListener(this);
|
wallet.setListener(this);
|
||||||
@@ -92,6 +83,7 @@ public class WalletService extends Service {
|
|||||||
|
|
||||||
void stop() {
|
void stop() {
|
||||||
Log.d(TAG, "MyWalletListener.stop()");
|
Log.d(TAG, "MyWalletListener.stop()");
|
||||||
|
Wallet wallet = getWallet();
|
||||||
if (wallet == null) throw new IllegalStateException("No wallet!");
|
if (wallet == null) throw new IllegalStateException("No wallet!");
|
||||||
wallet.pauseRefresh();
|
wallet.pauseRefresh();
|
||||||
wallet.setListener(null);
|
wallet.setListener(null);
|
||||||
@@ -115,6 +107,7 @@ public class WalletService extends Service {
|
|||||||
int lastTxCount = 0;
|
int lastTxCount = 0;
|
||||||
|
|
||||||
public void newBlock(long height) {
|
public void newBlock(long height) {
|
||||||
|
Wallet wallet = getWallet();
|
||||||
if (wallet == null) throw new IllegalStateException("No wallet!");
|
if (wallet == null) throw new IllegalStateException("No wallet!");
|
||||||
// don't flood with an update for every block ...
|
// don't flood with an update for every block ...
|
||||||
if (lastBlockTime < System.currentTimeMillis() - 2000) {
|
if (lastBlockTime < System.currentTimeMillis() - 2000) {
|
||||||
@@ -141,14 +134,16 @@ public class WalletService extends Service {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void updated() {
|
public void updated() {
|
||||||
Log.d(TAG, "updated() " + wallet.getBalance());
|
Log.d(TAG, "updated()");
|
||||||
|
Wallet wallet = getWallet();
|
||||||
if (wallet == null) throw new IllegalStateException("No wallet!");
|
if (wallet == null) throw new IllegalStateException("No wallet!");
|
||||||
updated = true;
|
updated = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void refreshed() {
|
public void refreshed() {
|
||||||
|
Log.d(TAG, "refreshed()");
|
||||||
|
Wallet wallet = getWallet();
|
||||||
if (wallet == null) throw new IllegalStateException("No wallet!");
|
if (wallet == null) throw new IllegalStateException("No wallet!");
|
||||||
Log.d(TAG, "refreshed() " + wallet.getName() + " " + wallet.getBalance() + " sync=" + wallet.isSynchronized() + " with observer " + observer);
|
|
||||||
if (updated) {
|
if (updated) {
|
||||||
if (observer != null) {
|
if (observer != null) {
|
||||||
updateDaemonState(wallet, 0);
|
updateDaemonState(wallet, 0);
|
||||||
@@ -253,8 +248,7 @@ public class WalletService extends Service {
|
|||||||
|
|
||||||
//
|
//
|
||||||
public Wallet getWallet() {
|
public Wallet getWallet() {
|
||||||
if (listener == null) throw new IllegalStateException("no listener");
|
return WalletManager.getInstance().getWallet();
|
||||||
return listener.getWallet();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/////////////////////////////////////////////
|
/////////////////////////////////////////////
|
||||||
@@ -441,10 +435,15 @@ public class WalletService extends Service {
|
|||||||
// start ID so we know which request we're stopping when we finish the job
|
// start ID so we know which request we're stopping when we finish the job
|
||||||
Message msg = mServiceHandler.obtainMessage();
|
Message msg = mServiceHandler.obtainMessage();
|
||||||
msg.arg2 = START_SERVICE;
|
msg.arg2 = START_SERVICE;
|
||||||
msg.setData(intent.getExtras());
|
if (intent != null) {
|
||||||
mServiceHandler.sendMessage(msg);
|
msg.setData(intent.getExtras());
|
||||||
//Log.d(TAG, "onStartCommand() message sent");
|
mServiceHandler.sendMessage(msg);
|
||||||
return START_STICKY;
|
return START_STICKY;
|
||||||
|
} else {
|
||||||
|
// process restart - don't do anything - let system kill it again
|
||||||
|
stop();
|
||||||
|
return START_NOT_STICKY;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -466,9 +465,8 @@ public class WalletService extends Service {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean start(String walletName, String walletPassword) {
|
private boolean start(String walletName, String walletPassword) {
|
||||||
startNotfication();
|
|
||||||
// if there is an listener it is always started / syncing
|
|
||||||
Log.d(TAG, "start()");
|
Log.d(TAG, "start()");
|
||||||
|
startNotfication();
|
||||||
showProgress(getString(R.string.status_wallet_loading));
|
showProgress(getString(R.string.status_wallet_loading));
|
||||||
showProgress(10);
|
showProgress(10);
|
||||||
if (listener == null) {
|
if (listener == null) {
|
||||||
@@ -478,7 +476,7 @@ public class WalletService extends Service {
|
|||||||
if (aWallet != null) aWallet.close();
|
if (aWallet != null) aWallet.close();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
listener = new MyWalletListener(aWallet);
|
listener = new MyWalletListener();
|
||||||
listener.start();
|
listener.start();
|
||||||
showProgress(100);
|
showProgress(100);
|
||||||
}
|
}
|
||||||
@@ -496,10 +494,6 @@ public class WalletService extends Service {
|
|||||||
if (listener != null) {
|
if (listener != null) {
|
||||||
listener.stop();
|
listener.stop();
|
||||||
Wallet myWallet = getWallet();
|
Wallet myWallet = getWallet();
|
||||||
// if (!myWallet.isSynchronized()) { // save only if NOT synced (to continue later)
|
|
||||||
// Log.d(TAG, "stop() saving");
|
|
||||||
// myWallet.store();
|
|
||||||
// }
|
|
||||||
Log.d(TAG, "stop() closing");
|
Log.d(TAG, "stop() closing");
|
||||||
myWallet.close();
|
myWallet.close();
|
||||||
Log.d(TAG, "stop() closed");
|
Log.d(TAG, "stop() closed");
|
||||||
@@ -561,6 +555,5 @@ public class WalletService extends Service {
|
|||||||
.setContentIntent(pendingIntent)
|
.setContentIntent(pendingIntent)
|
||||||
.build();
|
.build();
|
||||||
startForeground(NOTIFICATION_ID, notification);
|
startForeground(NOTIFICATION_ID, notification);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
9
app/src/main/res/drawable/ic_help_black_24dp.xml
Normal file
9
app/src/main/res/drawable/ic_help_black_24dp.xml
Normal file
@@ -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="#FF000000"
|
||||||
|
android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM13,19h-2v-2h2v2zM15.07,11.25l-0.9,0.92C13.45,12.9 13,13.5 13,15h-2v-0.5c0,-1.1 0.45,-2.1 1.17,-2.83l1.24,-1.26c0.37,-0.36 0.59,-0.86 0.59,-1.41 0,-1.1 -0.9,-2 -2,-2s-2,0.9 -2,2L8,9c0,-2.21 1.79,-4 4,-4s4,1.79 4,4c0,0.88 -0.36,1.68 -0.93,2.25z"/>
|
||||||
|
</vector>
|
29
app/src/main/res/layout/help_fragment.xml
Normal file
29
app/src/main/res/layout/help_fragment.xml
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
|
||||||
|
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/helpFragmentIcon"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:src="@mipmap/ic_launcher"
|
||||||
|
android:padding="8sp"/>
|
||||||
|
|
||||||
|
<WebView
|
||||||
|
android:id="@+id/helpFragmentWebView"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_below="@+id/helpFragmentIcon"
|
||||||
|
android:visibility="invisible" />
|
||||||
|
|
||||||
|
<ProgressBar
|
||||||
|
android:id="@+id/helpFragmentProgress"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_centerInParent="true"
|
||||||
|
android:indeterminate="true" />
|
||||||
|
|
||||||
|
</RelativeLayout>
|
@@ -6,18 +6,18 @@
|
|||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/icon"
|
android:id="@+id/licensesFragmentIcon"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:src="@mipmap/ic_launcher"
|
android:src="@mipmap/ic_launcher"
|
||||||
android:padding="8sp"/>
|
android:padding="8sp"/>
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/text"
|
android:id="@+id/licensesFragmentText"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@string/about_text"
|
android:text="@string/about_text"
|
||||||
android:layout_below="@+id/icon"
|
android:layout_below="@+id/licensesFragmentIcon"
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:layout_marginBottom="8sp"/>
|
android:layout_marginBottom="8sp"/>
|
||||||
|
|
||||||
@@ -25,7 +25,7 @@
|
|||||||
android:id="@+id/licensesFragmentWebView"
|
android:id="@+id/licensesFragmentWebView"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:layout_below="@+id/text"
|
android:layout_below="@+id/licensesFragmentText"
|
||||||
android:visibility="invisible" />
|
android:visibility="invisible" />
|
||||||
|
|
||||||
<ProgressBar
|
<ProgressBar
|
||||||
|
12
app/src/main/res/menu/create_wallet_menu.xml
Normal file
12
app/src/main/res/menu/create_wallet_menu.xml
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<?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/action_create_help"
|
||||||
|
android:icon="@drawable/ic_help_black_24dp"
|
||||||
|
android:orderInCategory="100"
|
||||||
|
android:title="@string/menu_help"
|
||||||
|
app:showAsAction="always" />
|
||||||
|
|
||||||
|
</menu>
|
12
app/src/main/res/menu/wallet_details_menu.xml
Normal file
12
app/src/main/res/menu/wallet_details_menu.xml
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<?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/action_details_help"
|
||||||
|
android:icon="@drawable/ic_help_black_24dp"
|
||||||
|
android:orderInCategory="100"
|
||||||
|
android:title="@string/menu_help"
|
||||||
|
app:showAsAction="always" />
|
||||||
|
|
||||||
|
</menu>
|
54
app/src/main/res/raw/help_create.html
Normal file
54
app/src/main/res/raw/help_create.html
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<style>body {font-family: sans-serif; font-size: 1em;}</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>Create Wallet</h1>
|
||||||
|
A wallet can be created in a number of ways:
|
||||||
|
<ul>
|
||||||
|
<li>New Address</li>
|
||||||
|
<li>Recover from Seed</li>
|
||||||
|
<li>Recover from Keys</li>
|
||||||
|
<li>View Only</li>
|
||||||
|
</ul>
|
||||||
|
In all cases you need to name your wallet and give it a password. The password is used for
|
||||||
|
securing your wallet data on the device. Use a strong password - even better use a passphrase.
|
||||||
|
|
||||||
|
<h2>New Address</h2>
|
||||||
|
You need a new Monero Address - no need to enter any additional info.
|
||||||
|
<h3>Take Note of your Mnemonic Seed!</h3>
|
||||||
|
<p>
|
||||||
|
On the following screen you will find your 25-word "Mnemonic Seed".
|
||||||
|
This is the only data needed to recover your wallet at a later point
|
||||||
|
and gain full access to your funds.
|
||||||
|
Keeping this secure and private is very important, as it gives <em>anyone</em>
|
||||||
|
full access to your funds!
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
If you lose your wallet password, you can still recover your wallet with the Mnemonic Seed.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
There is no way to recover your Mnemonic Seed, if you lose it all your funds will be lost!
|
||||||
|
The Mnemonic Seed can also never be changed, and if it is stolen or otherwise compromised,
|
||||||
|
you will have to move your funds to new wallet (with a new Mnemonic Seed). Therefore, it is best
|
||||||
|
that you backup your Mnemonic Seed by writing it down and storing it in <em>multiple</em> safe
|
||||||
|
and secure places.
|
||||||
|
</p>
|
||||||
|
<h2>Recover from Seed</h2>
|
||||||
|
If you already have a Monero Address and want to recover the transactions from the blockchain.<br/>
|
||||||
|
Enter your Seed in the field "Mnemonic Seed". If you know the block number of the first
|
||||||
|
transaction used for this address, enter it in the field "Restore Height" - leaving it blank will
|
||||||
|
scan the <em>entire</em> blockchain for transactions belonging to your address.
|
||||||
|
This takes a <em>long</em> time.
|
||||||
|
|
||||||
|
<h2>Recover from Keys</h2>
|
||||||
|
Instead of recovering from the Mnemonic Seed, you can recover using your keys.<br/>
|
||||||
|
Enter your Monero Address in the field "Public Address" and fill out "View Key", "Spend Key"
|
||||||
|
and optionally "Restore Height" with the appropriate values.
|
||||||
|
|
||||||
|
<h2>View Only</h2>
|
||||||
|
If you just want to monitor incoming transactions to a wallet.<br/>
|
||||||
|
Enter your Monero Address in the field "Public Address" and fill out the "View Key" and
|
||||||
|
optionally "Restore Height" with the appropriate values leaving the "Spend Key" blank.
|
||||||
|
</body>
|
||||||
|
</html>
|
44
app/src/main/res/raw/help_details.html
Normal file
44
app/src/main/res/raw/help_details.html
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<style>body {font-family: sans-serif; font-size: 1em;}</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>Wallet Details</h1>
|
||||||
|
Here you see the details of your wallet.
|
||||||
|
<ul>
|
||||||
|
<li>Mnemonic Seed</li>
|
||||||
|
<li>Public Address</li>
|
||||||
|
<li>View Key</li>
|
||||||
|
<li>Spend Key</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h2>Mnemonic Seed</h2>
|
||||||
|
<p>
|
||||||
|
Your 25-word "Mnemonic Seed". This is the only data needed to recover your wallet at a later
|
||||||
|
point and gain full access to your funds.
|
||||||
|
Keeping this secure and private is very important, as it gives <em>anyone</em>
|
||||||
|
full access to your funds!
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
If you lose your wallet password, you can still recover your wallet with the Mnemonic Seed.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
There is no way to recover your Mnemonic Seed, if you lose it all your funds will be lost!
|
||||||
|
The Mnemonic Seed can also never be changed, and if it is stolen or otherwise compromised,
|
||||||
|
you will have to move your funds to new wallet (with a new Mnemonic Seed). Therefore, it is best
|
||||||
|
that you backup your Mnemonic Seed by writing it down and storing it in <em>multiple</em> safe
|
||||||
|
and secure places.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h2>Public Address</h2>
|
||||||
|
This is your account number. You use it to receive funds. A sender needs to know nothing
|
||||||
|
more than this address to send you Monero.
|
||||||
|
|
||||||
|
<h2>View Key</h2>
|
||||||
|
This key is required for creating a view-only wallet or for recovering from keys.
|
||||||
|
|
||||||
|
<h2>Spend Key</h2>
|
||||||
|
This is key is required for recovering from keys.
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
@@ -6,6 +6,7 @@
|
|||||||
<string name="menu_testnet">Testnet</string>
|
<string name="menu_testnet">Testnet</string>
|
||||||
<string name="menu_about">About …</string>
|
<string name="menu_about">About …</string>
|
||||||
|
|
||||||
|
<string name="menu_help">Help</string>
|
||||||
<string name="menu_info">Details</string>
|
<string name="menu_info">Details</string>
|
||||||
<string name="menu_receive">QR Receive</string>
|
<string name="menu_receive">QR Receive</string>
|
||||||
<string name="menu_rename">Rename</string>
|
<string name="menu_rename">Rename</string>
|
||||||
@@ -82,6 +83,9 @@
|
|||||||
<string name="message_strorage_not_permitted">We really need those External Storage permissions!</string>
|
<string name="message_strorage_not_permitted">We really need those External Storage permissions!</string>
|
||||||
<string name="message_camera_not_permitted">No camera = No QR scanning!</string>
|
<string name="message_camera_not_permitted">No camera = No QR scanning!</string>
|
||||||
|
|
||||||
|
<string name="message_noselect_seed">Selecting seed disabled for security reasons!</string>
|
||||||
|
<string name="message_noselect_key">Selecting spend key disabled for security reasons!</string>
|
||||||
|
|
||||||
<string name="generate_title">Create Wallet</string>
|
<string name="generate_title">Create Wallet</string>
|
||||||
<string name="generate_name_hint">Wallet Name</string>
|
<string name="generate_name_hint">Wallet Name</string>
|
||||||
<string name="generate_password_hint">Wallet Password</string>
|
<string name="generate_password_hint">Wallet Password</string>
|
||||||
@@ -100,8 +104,6 @@
|
|||||||
<string name="generate_wallet_creating">Creating wallet</string>
|
<string name="generate_wallet_creating">Creating wallet</string>
|
||||||
<string name="generate_wallet_created">Wallet created</string>
|
<string name="generate_wallet_created">Wallet created</string>
|
||||||
<string name="generate_wallet_create_failed">Wallet create failed</string>
|
<string name="generate_wallet_create_failed">Wallet create failed</string>
|
||||||
<string name="generate_wallet_create_failed_1">Wallet create failed (1/2)</string>
|
|
||||||
<string name="generate_wallet_create_failed_2">Wallet create failed (2/2)</string>
|
|
||||||
<string name="generate_address_placeholder">9tDC52GsMjTNt4dpnRCwAF7ekVBkbkgkXGaMKTcSTpBhGpqkPX56jCNRydLq9oGjbbAQBsZhLfgmTKsntmxRd3TaJFYM2f8</string>
|
<string name="generate_address_placeholder">9tDC52GsMjTNt4dpnRCwAF7ekVBkbkgkXGaMKTcSTpBhGpqkPX56jCNRydLq9oGjbbAQBsZhLfgmTKsntmxRd3TaJFYM2f8</string>
|
||||||
<string name="generate_viewkey_placeholder">e2b99f4cc3d644774c4b118db05f8aa9967583a01ca4d47058c3860af10bd306</string>
|
<string name="generate_viewkey_placeholder">e2b99f4cc3d644774c4b118db05f8aa9967583a01ca4d47058c3860af10bd306</string>
|
||||||
<string name="generate_spendkey_placeholder">300a54208ab0a638a8407a12e3de946da76f5a9ded303338452332ec7755210d</string>
|
<string name="generate_spendkey_placeholder">300a54208ab0a638a8407a12e3de946da76f5a9ded303338452332ec7755210d</string>
|
||||||
|
@@ -8,7 +8,7 @@ replacing "32" with "64".
|
|||||||
## Prepare Ubuntu environment
|
## Prepare Ubuntu environment
|
||||||
|
|
||||||
```
|
```
|
||||||
sudo apt-get install build-essential cmake tofrodos
|
sudo apt-get install build-essential cmake tofrodos libtool-bin
|
||||||
sudo mkdir /opt/android
|
sudo mkdir /opt/android
|
||||||
sudo chown $LOGNAME /opt/android
|
sudo chown $LOGNAME /opt/android
|
||||||
```
|
```
|
||||||
@@ -70,9 +70,9 @@ ln -s ../../../../openssl/android-21/lib/libcrypto.so
|
|||||||
## Build Boost
|
## Build Boost
|
||||||
```
|
```
|
||||||
cd /opt/android
|
cd /opt/android
|
||||||
wget https://sourceforge.net/projects/boost/files/boost/1.64.0/boost_1_64_0.tar.gz/download -O boost_1_64_0.tar.gz
|
wget https://sourceforge.net/projects/boost/files/boost/1.58.0/boost_1_58_0.tar.gz/download -O boost_1_58_0.tar.gz
|
||||||
tar xfz boost_1_64_0.tar.gz
|
tar xfz boost_1_58_0.tar.gz
|
||||||
(cd boost_1_64_0; ./bootstrap.sh)
|
(cd boost_1_58_0; ./bootstrap.sh)
|
||||||
```
|
```
|
||||||
The NDK r15c above gives errors about fsetpos and fgetpos not found(!?!), so we "just" comment them out in the include file:
|
The NDK r15c above gives errors about fsetpos and fgetpos not found(!?!), so we "just" comment them out in the include file:
|
||||||
`nano /opt/android/tool32/include/c++/4.9.x/cstdio` (`//using ::fgetpos`, `//using ::fsetpos`)
|
`nano /opt/android/tool32/include/c++/4.9.x/cstdio` (`//using ::fgetpos`, `//using ::fsetpos`)
|
||||||
@@ -83,21 +83,57 @@ export PATH=/opt/android/tool32/arm-linux-androideabi/bin:/opt/android/tool32/bi
|
|||||||
./b2 --build-type=minimal link=static runtime-link=static --with-chrono --with-date_time --with-filesystem --with-program_options --with-regex --with-serialization --with-system --with-thread --build-dir=android32 --stagedir=android32 toolset=clang threading=multi threadapi=pthread target-os=android stage
|
./b2 --build-type=minimal link=static runtime-link=static --with-chrono --with-date_time --with-filesystem --with-program_options --with-regex --with-serialization --with-system --with-thread --build-dir=android32 --stagedir=android32 toolset=clang threading=multi threadapi=pthread target-os=android stage
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Build & prepare zeromq
|
||||||
|
Only needed for zeromq versions (>v0.11.0.0).
|
||||||
|
```
|
||||||
|
cd /opt/android
|
||||||
|
wget git clone https://github.com/zeromq/zeromq3-x.git
|
||||||
|
export PATH=/opt/android/tool32/arm-linux-androideabi/bin:/opt/android/tool32/bin:$PATH
|
||||||
|
export OUTPUT_DIR=/opt/android/zeromq
|
||||||
|
./configure --enable-static --disable-shared --host=arm-linux-androideabi --prefix=$OUTPUT_DIR LDFLAGS="-L$OUTPUT_DIR/lib" CPPFLAGS="-isystem /opt/android/tool32/include/c++/4.9.x -fPIC -I$OUTPUT_DIR/include -Wno-error -D__ANDROID_API__=21" LIBS="-lgcc"
|
||||||
|
make
|
||||||
|
make install
|
||||||
|
|
||||||
|
git clone https://github.com/zeromq/cppzmq.git
|
||||||
|
cp cppzmq/*.hpp zeromq/include/
|
||||||
|
```
|
||||||
|
|
||||||
## And finally: Build Monero
|
## And finally: Build Monero
|
||||||
```
|
```
|
||||||
cd /opt/android
|
cd /opt/android
|
||||||
git clone https://github.com/monero-project/monero
|
git clone https://github.com/monero-project/monero
|
||||||
cd monero
|
cd monero
|
||||||
|
```
|
||||||
|
```
|
||||||
# <patch monero code as needed>
|
# <patch monero code as needed>
|
||||||
|
# also, don't abort on warnings (this is only an issue >v0.11.0.0):
|
||||||
|
diff --git a/CMakeLists.txt b/CMakeLists.txt
|
||||||
|
index 1f74f59..2c791c0 100644
|
||||||
|
--- a/CMakeLists.txt
|
||||||
|
+++ b/CMakeLists.txt
|
||||||
|
@@ -400,7 +400,7 @@ else()
|
||||||
|
set(ARCH_FLAG "-march=${ARCH}")
|
||||||
|
endif()
|
||||||
|
set(WARNINGS "-Wall -Wextra -Wpointer-arith -Wundef -Wvla -Wwrite-strings -Wno-error=extra -Wno-error=deprecated-declarations -Wno-unused-parameter -Wno-unused-variable -Wno-error=unused-variable -Wno-error=undef -Wno-error=uninitialized")
|
||||||
|
- if(NOT MINGW)
|
||||||
|
+ if(NOT MINGW AND NOT ANDROID)
|
||||||
|
set(WARNINGS_AS_ERRORS_FLAG "-Werror")
|
||||||
|
endif()
|
||||||
|
if(CMAKE_C_COMPILER_ID STREQUAL "Clang")
|
||||||
|
```
|
||||||
|
```
|
||||||
mkdir -p build/release.android32
|
mkdir -p build/release.android32
|
||||||
cd build/release.android32
|
cd build/release.android32
|
||||||
|
|
||||||
# only if not set already set
|
# only if not set already set
|
||||||
export PATH=/opt/android/tool32/arm-linux-androideabi/bin:/opt/android/tool32/bin:$PATH
|
export PATH=/opt/android/tool32/arm-linux-androideabi/bin:/opt/android/tool32/bin:$PATH
|
||||||
|
|
||||||
CC=clang CXX=clang++ cmake -D BUILD_TESTS=OFF -D ARCH="armv7-a" -D STATIC=ON -D BUILD_64=OFF -D CMAKE_BUILD_TYPE=release -D ANDROID=true -D BUILD_TAG="android" -D BOOST_ROOT=/opt/android/boost_1_64_0 -D BOOST_LIBRARYDIR=/opt/android/boost_1_64_0/android32/lib -D OPENSSL_ROOT_DIR=/opt/android/openssl/android-21 -D CMAKE_POSITION_INDEPENDENT_CODE:BOOL=true ../..
|
# for zeromq versions (>v0.11.0.0).
|
||||||
|
CC=clang CXX=clang++ cmake -D BUILD_TESTS=OFF -D ARCH="armv7-a" -D STATIC=ON -D BUILD_64=OFF -D CMAKE_BUILD_TYPE=release -D ANDROID=true -D BUILD_TAG="android" -D BOOST_ROOT=/opt/android/boost_1_58_0 -D BOOST_LIBRARYDIR=/opt/android/boost_1_58_0/android32/lib -D OPENSSL_ROOT_DIR=/opt/android/openssl/android-21 -D CMAKE_POSITION_INDEPENDENT_CODE:BOOL=true -D ZMQ_INCLUDE_PATH=/opt/android/zeromq/include -D ZMQ_LIB=/opt/android/zeromq/lib/libzmq.a ../..
|
||||||
|
|
||||||
|
# for pre-zeromq versions (<=v0.11.0.0).
|
||||||
|
CC=clang CXX=clang++ cmake -D BUILD_TESTS=OFF -D ARCH="armv7-a" -D STATIC=ON -D BUILD_64=OFF -D CMAKE_BUILD_TYPE=release -D ANDROID=true -D BUILD_TAG="android" -D BOOST_ROOT=/opt/android/boost_1_58_0 -D BOOST_LIBRARYDIR=/opt/android/boost_1_58_0/android32/lib -D OPENSSL_ROOT_DIR=/opt/android/openssl/android-21 -D CMAKE_POSITION_INDEPENDENT_CODE:BOOL=true ../..
|
||||||
|
|
||||||
make
|
make
|
||||||
|
|
||||||
find . -name '*.a' -exec cp '{}' lib \;
|
find . -name '*.a' -exec cp '{}' lib \;
|
||||||
|
@@ -22,7 +22,7 @@
|
|||||||
- All significant figures shown in balance
|
- All significant figures shown in balance
|
||||||
- QR Code scanning - make sure to *ALWAYS* verify the scanned code is what it is advertised to be!
|
- QR Code scanning - make sure to *ALWAYS* verify the scanned code is what it is advertised to be!
|
||||||
- QR Code for receiving with conversion of XMR to USD/EUR and back through kraken API
|
- QR Code for receiving with conversion of XMR to USD/EUR and back through kraken API
|
||||||
- Backup wallets to ```.backups``` folder in main wallet folder (old backups are overwritten)
|
- Backup wallets to ```backups``` folder in main wallet folder (old backups are overwritten)
|
||||||
- Rename wallets
|
- Rename wallets
|
||||||
- Archive (=Backup and delete)
|
- Archive (=Backup and delete)
|
||||||
- 3 Default nodes + History of last 5 used nodes
|
- 3 Default nodes + History of last 5 used nodes
|
||||||
|
@@ -1,4 +1,11 @@
|
|||||||
# Privacy Policy
|
# Privacy Policy
|
||||||
|
|
||||||
All data entered in the monerujo app is stored locally on the device and is not collected remotely or otherwise processed except
|
All data entered in the Monerujo app is stored locally on the device and is not collected remotely or otherwise processed except
|
||||||
for the purpose of processing transactions in the monero network in encrypted form.
|
for the purpose of processing transactions in the Monero Network in encrypted form.
|
||||||
|
|
||||||
|
## App permissions
|
||||||
|
- INTERNET : Connect to the Monero Network via Monero Daemon Node
|
||||||
|
- READ_EXTERNAL_STORAGE : Read wallets
|
||||||
|
- WRITE_EXTERNAL_STORAGE : Write wallets
|
||||||
|
- WAKE_LOCK : Keep device awake while syncing
|
||||||
|
- CAMERA : Scan QR Codes
|
||||||
|
Reference in New Issue
Block a user