mirror of
https://github.com/m2049r/xmrwallet
synced 2025-09-03 08:23:04 +02:00
Compare commits
181 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
4a819cc159 | ||
![]() |
f40c3d6c6d | ||
![]() |
82b25df7ad | ||
![]() |
08f815e830 | ||
![]() |
4e59be2dff | ||
![]() |
45c5883e11 | ||
![]() |
067a23e6a5 | ||
![]() |
d21fd41c44 | ||
![]() |
6632547d1e | ||
![]() |
f1b786ec3e | ||
![]() |
a93e96d34c | ||
![]() |
1829d30b61 | ||
![]() |
e5b15b7816 | ||
![]() |
7206857a5b | ||
![]() |
85d84d09ee | ||
![]() |
c6a1b503bc | ||
![]() |
8bda7aa0cf | ||
![]() |
97fb0a5483 | ||
![]() |
fc950c6772 | ||
![]() |
46add5e927 | ||
![]() |
fa0692ceab | ||
![]() |
ff4f4a1c2c | ||
![]() |
79abb89725 | ||
![]() |
ef8301fd6f | ||
![]() |
3a15c842ff | ||
![]() |
1697da55b5 | ||
![]() |
454f3e412a | ||
![]() |
d803a1e220 | ||
![]() |
f2fe781cb5 | ||
![]() |
dcf60ae193 | ||
![]() |
ffdf54c2e1 | ||
![]() |
c060a2ab88 | ||
![]() |
05fc654f3a | ||
![]() |
c32d157150 | ||
![]() |
74e9278baa | ||
![]() |
e41e344d63 | ||
![]() |
e66875437d | ||
![]() |
c1d2db3d7d | ||
![]() |
0c9a2f5e01 | ||
![]() |
64616e3921 | ||
![]() |
82b4d66987 | ||
![]() |
10f2bc6561 | ||
![]() |
2ed9a78d9e | ||
![]() |
ca19f32f8f | ||
![]() |
4431d74051 | ||
![]() |
f00da6ecda | ||
![]() |
1cecd0b718 | ||
![]() |
a0d6117bbb | ||
![]() |
0b0648a172 | ||
![]() |
775dcf01ae | ||
![]() |
aed4051d44 | ||
![]() |
a586c0781a | ||
![]() |
616d93cb18 | ||
![]() |
73d9cb6d58 | ||
![]() |
9846e8b5cf | ||
![]() |
aa66a12dac | ||
![]() |
65ce9b0889 | ||
![]() |
291e311b8a | ||
![]() |
41290f51fd | ||
![]() |
a11c898e2c | ||
![]() |
9c921183ab | ||
![]() |
b978396a38 | ||
![]() |
c6aa04e986 | ||
![]() |
6c17b8bd87 | ||
![]() |
835a35c6a8 | ||
![]() |
cac32f660c | ||
![]() |
8e70004bf2 | ||
![]() |
c3a466c392 | ||
![]() |
e076c19e3e | ||
![]() |
35b717756d | ||
![]() |
c14486306e | ||
![]() |
c2ef25c377 | ||
![]() |
b7164ef200 | ||
![]() |
f94a366d51 | ||
![]() |
286a04b5ef | ||
![]() |
1209295a8c | ||
![]() |
037b019d4d | ||
![]() |
7a1d788f2a | ||
![]() |
87d9a8cd95 | ||
![]() |
f637d7f617 | ||
![]() |
a4b9a7c6fb | ||
![]() |
9f01155cb7 | ||
![]() |
08e8a48138 | ||
![]() |
551c3b9fb6 | ||
![]() |
2258cb7096 | ||
![]() |
6d61841cf3 | ||
![]() |
c65508d288 | ||
![]() |
2c3f582672 | ||
![]() |
f46ba75771 | ||
![]() |
0ce5f2b6ca | ||
![]() |
110057c294 | ||
![]() |
7553d3c5f4 | ||
![]() |
317976b34a | ||
![]() |
6ad423567f | ||
![]() |
d497158856 | ||
![]() |
f4cada5fa1 | ||
![]() |
352f0ad09c | ||
![]() |
ff1a9c1570 | ||
![]() |
fa811a39a2 | ||
![]() |
cf5018be33 | ||
![]() |
8ec027f9d4 | ||
![]() |
f28428e677 | ||
![]() |
294084bec5 | ||
![]() |
4349907627 | ||
![]() |
f7cef24a83 | ||
![]() |
2774f99b15 | ||
![]() |
bc630fc445 | ||
![]() |
895cf16d33 | ||
![]() |
7f1796b12e | ||
![]() |
abe5c8afab | ||
![]() |
47f79b5269 | ||
![]() |
c9c07eaa15 | ||
![]() |
a490e3af0c | ||
![]() |
64d5b3bdea | ||
![]() |
bf91eaf22f | ||
![]() |
2c3e73b540 | ||
![]() |
830d9dadb9 | ||
![]() |
331d88ebba | ||
![]() |
7cc2f6fafb | ||
![]() |
9a3ee0eda8 | ||
![]() |
6e898939a3 | ||
![]() |
40ae39d647 | ||
![]() |
ca81e652e5 | ||
![]() |
796048be4e | ||
![]() |
441bf995c8 | ||
![]() |
e8860ab8eb | ||
![]() |
525b38ff53 | ||
![]() |
ba79bf87aa | ||
![]() |
3fe6571e7d | ||
![]() |
364e6a8137 | ||
![]() |
cb69ce99d6 | ||
![]() |
1f976872fc | ||
![]() |
27f266b6f7 | ||
![]() |
168928d54a | ||
![]() |
b3f61072aa | ||
![]() |
ccb64aded0 | ||
![]() |
e98fa089f2 | ||
![]() |
884878b7a7 | ||
![]() |
4e23f0ef3a | ||
![]() |
6ea4e3d998 | ||
![]() |
971c90f35b | ||
![]() |
f0523c403c | ||
![]() |
966ed23b87 | ||
![]() |
95f2ca74a6 | ||
![]() |
81d94478f2 | ||
![]() |
16ff779ebc | ||
![]() |
6b7bb164f4 | ||
![]() |
da1d4ea1bf | ||
![]() |
d5a967f690 | ||
![]() |
de8de02f9f | ||
![]() |
06456e33e4 | ||
![]() |
d97b36aa44 | ||
![]() |
8fa06e5b37 | ||
![]() |
8d95de828b | ||
![]() |
93a7be0452 | ||
![]() |
25c8ec1229 | ||
![]() |
0bf0444dce | ||
![]() |
b74f9c6bd7 | ||
![]() |
f843bb1685 | ||
![]() |
7d9d49c29e | ||
![]() |
4ca9328949 | ||
![]() |
08b5a87f19 | ||
![]() |
445d8acc38 | ||
![]() |
9385ac8c31 | ||
![]() |
4c7ebd8402 | ||
![]() |
67f3c5f948 | ||
![]() |
cd67a7e2bf | ||
![]() |
fa5fe313ea | ||
![]() |
ed4957a3cc | ||
![]() |
3e0eeebd51 | ||
![]() |
0d213a1eb4 | ||
![]() |
39d048fd5e | ||
![]() |
1a5d2d0399 | ||
![]() |
028057a672 | ||
![]() |
909ff8ca5e | ||
![]() |
ffd61e4495 | ||
![]() |
003dee382e | ||
![]() |
be0498c67d | ||
![]() |
06227a4a83 | ||
![]() |
4409087bd0 | ||
![]() |
965e52d8a5 |
@@ -3,11 +3,13 @@ jobs:
|
||||
build:
|
||||
working_directory: ~/code
|
||||
docker:
|
||||
- image: bitriseio/android-ndk
|
||||
- image: circleci/android:api-28-ndk
|
||||
environment:
|
||||
JVM_OPTS: -Xmx3200m
|
||||
steps:
|
||||
- checkout
|
||||
- run: yes | sdkmanager --licenses || exit 0
|
||||
- run: yes | sdkmanager --update || exit 0
|
||||
- restore_cache:
|
||||
key: jars-{{ checksum "build.gradle" }}-{{ checksum "app/build.gradle" }}
|
||||
- run:
|
||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@@ -14,3 +14,4 @@
|
||||
/app/prodMainnet
|
||||
/app/alphaStagenet
|
||||
/app/prodStagenet
|
||||
/app/.cxx
|
||||
|
3
.idea/.gitignore
generated
vendored
3
.idea/.gitignore
generated
vendored
@@ -1,3 +0,0 @@
|
||||
workspace.xml
|
||||
markdown-*
|
||||
misc.xml
|
1
.idea/.name
generated
1
.idea/.name
generated
@@ -1 +0,0 @@
|
||||
xmrwallet
|
22
.idea/compiler.xml
generated
22
.idea/compiler.xml
generated
@@ -1,22 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="CompilerConfiguration">
|
||||
<resourceExtensions />
|
||||
<wildcardResourcePatterns>
|
||||
<entry name="!?*.java" />
|
||||
<entry name="!?*.form" />
|
||||
<entry name="!?*.class" />
|
||||
<entry name="!?*.groovy" />
|
||||
<entry name="!?*.scala" />
|
||||
<entry name="!?*.flex" />
|
||||
<entry name="!?*.kt" />
|
||||
<entry name="!?*.clj" />
|
||||
<entry name="!?*.aj" />
|
||||
</wildcardResourcePatterns>
|
||||
<annotationProcessing>
|
||||
<profile default="true" name="Default" enabled="false">
|
||||
<processorPath useClasspath="true" />
|
||||
</profile>
|
||||
</annotationProcessing>
|
||||
</component>
|
||||
</project>
|
3
.idea/copyright/profiles_settings.xml
generated
3
.idea/copyright/profiles_settings.xml
generated
@@ -1,3 +0,0 @@
|
||||
<component name="CopyrightManager">
|
||||
<settings default="" />
|
||||
</component>
|
19
.idea/gradle.xml
generated
19
.idea/gradle.xml
generated
@@ -1,19 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="GradleSettings">
|
||||
<option name="linkedExternalProjectsSettings">
|
||||
<GradleProjectSettings>
|
||||
<option name="disableWrapperSourceDistributionNotification" value="true" />
|
||||
<option name="distributionType" value="DEFAULT_WRAPPED" />
|
||||
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
||||
<option name="modules">
|
||||
<set>
|
||||
<option value="$PROJECT_DIR$" />
|
||||
<option value="$PROJECT_DIR$/app" />
|
||||
</set>
|
||||
</option>
|
||||
<option name="resolveModulePerSourceSet" value="false" />
|
||||
</GradleProjectSettings>
|
||||
</option>
|
||||
</component>
|
||||
</project>
|
9
.idea/modules.xml
generated
9
.idea/modules.xml
generated
@@ -1,9 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/app/app.iml" filepath="$PROJECT_DIR$/app/app.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/xmrwallet.iml" filepath="$PROJECT_DIR$/xmrwallet.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
12
.idea/runConfigurations.xml
generated
12
.idea/runConfigurations.xml
generated
@@ -1,12 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="RunConfigurationProducerService">
|
||||
<option name="ignoredProducers">
|
||||
<set>
|
||||
<option value="org.jetbrains.plugins.gradle.execution.test.runner.AllInPackageGradleConfigurationProducer" />
|
||||
<option value="org.jetbrains.plugins.gradle.execution.test.runner.TestClassGradleConfigurationProducer" />
|
||||
<option value="org.jetbrains.plugins.gradle.execution.test.runner.TestMethodGradleConfigurationProducer" />
|
||||
</set>
|
||||
</option>
|
||||
</component>
|
||||
</project>
|
6
.idea/vcs.xml
generated
6
.idea/vcs.xml
generated
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
@@ -137,7 +137,11 @@ set_target_properties(checkpoints PROPERTIES IMPORTED_LOCATION
|
||||
|
||||
add_library(device STATIC IMPORTED)
|
||||
set_target_properties(device PROPERTIES IMPORTED_LOCATION
|
||||
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libdevice.a)
|
||||
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libdevice.a)
|
||||
|
||||
add_library(device_trezor STATIC IMPORTED)
|
||||
set_target_properties(device_trezor PROPERTIES IMPORTED_LOCATION
|
||||
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libdevice_trezor.a)
|
||||
|
||||
add_library(multisig STATIC IMPORTED)
|
||||
set_target_properties(multisig PROPERTIES IMPORTED_LOCATION
|
||||
@@ -147,6 +151,22 @@ add_library(version STATIC IMPORTED)
|
||||
set_target_properties(version PROPERTIES IMPORTED_LOCATION
|
||||
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libversion.a)
|
||||
|
||||
add_library(net STATIC IMPORTED)
|
||||
set_target_properties(net PROPERTIES IMPORTED_LOCATION
|
||||
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libnet.a)
|
||||
|
||||
add_library(hardforks STATIC IMPORTED)
|
||||
set_target_properties(hardforks PROPERTIES IMPORTED_LOCATION
|
||||
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libhardforks.a)
|
||||
|
||||
add_library(randomx STATIC IMPORTED)
|
||||
set_target_properties(randomx PROPERTIES IMPORTED_LOCATION
|
||||
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/librandomx.a)
|
||||
|
||||
add_library(rpc_base STATIC IMPORTED)
|
||||
set_target_properties(rpc_base PROPERTIES IMPORTED_LOCATION
|
||||
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/librpc_base.a)
|
||||
|
||||
#############
|
||||
# System
|
||||
#############
|
||||
@@ -166,6 +186,7 @@ target_link_libraries( monerujo
|
||||
mnemonics
|
||||
ringct
|
||||
ringct_basic
|
||||
net
|
||||
common
|
||||
cncrypto
|
||||
blockchain_db
|
||||
@@ -176,8 +197,12 @@ target_link_libraries( monerujo
|
||||
blocks
|
||||
checkpoints
|
||||
device
|
||||
device_trezor
|
||||
multisig
|
||||
version
|
||||
randomx
|
||||
hardforks
|
||||
rpc_base
|
||||
|
||||
boost_chrono
|
||||
boost_date_time
|
||||
|
@@ -1,16 +1,15 @@
|
||||
apply plugin: 'com.android.application'
|
||||
|
||||
android {
|
||||
compileSdkVersion 28
|
||||
buildToolsVersion '28.0.3'
|
||||
compileSdkVersion 30
|
||||
buildToolsVersion '29.0.2'
|
||||
defaultConfig {
|
||||
applicationId "com.m2049r.xmrwallet"
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 28
|
||||
versionCode 163
|
||||
versionName "1.10.13 'Node-O-matiC'"
|
||||
|
||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||
targetSdkVersion 30
|
||||
versionCode 601
|
||||
versionName "1.16.1 'Karmic Nodes'"
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
externalNativeBuild {
|
||||
cmake {
|
||||
cppFlags "-std=c++11"
|
||||
@@ -18,6 +17,11 @@ android {
|
||||
}
|
||||
}
|
||||
}
|
||||
bundle {
|
||||
language {
|
||||
enableSplit = false
|
||||
}
|
||||
}
|
||||
|
||||
flavorDimensions 'type', 'net'
|
||||
productFlavors {
|
||||
@@ -29,6 +33,11 @@ android {
|
||||
applicationIdSuffix '.stage'
|
||||
versionNameSuffix ' (stage)'
|
||||
}
|
||||
devnet {
|
||||
dimension 'net'
|
||||
applicationIdSuffix '.test'
|
||||
versionNameSuffix ' (test)'
|
||||
}
|
||||
alpha {
|
||||
dimension 'type'
|
||||
applicationIdSuffix '.alpha'
|
||||
@@ -71,7 +80,8 @@ android {
|
||||
def availableLocales = ["en"]
|
||||
new File("app/src/main/res/").eachFileMatch(~/^values-.*/) { file ->
|
||||
def languageTag = file.name.substring(7).replace("-r", "-")
|
||||
availableLocales.add(languageTag)
|
||||
if (languageTag != "night")
|
||||
availableLocales.add(languageTag)
|
||||
}
|
||||
|
||||
// APKs for the same app that all have the same version information.
|
||||
@@ -82,8 +92,7 @@ android {
|
||||
variant.outputs.all {
|
||||
output ->
|
||||
def abiName = output.getFilter(com.android.build.OutputFile.ABI)
|
||||
output.versionCodeOverride = abiCodes.get(abiName, 0) + 10 * variant.versionCode
|
||||
//def flavor = output.getFilter(flavor)
|
||||
output.versionCodeOverride = abiCodes.get(abiName, 0) + 10 * versionCode
|
||||
|
||||
if (abiName == null) abiName = "universal"
|
||||
def v = "${variant.versionName}".replaceFirst(" '.*' ?", "")
|
||||
@@ -93,30 +102,43 @@ android {
|
||||
outputFileName = "$rootProject.ext.apkName-" + v + "_" + abiName + ".apk"
|
||||
}
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation "com.android.support:appcompat-v7:$rootProject.ext.supportVersion"
|
||||
implementation "com.android.support:design:$rootProject.ext.supportVersion"
|
||||
implementation "com.android.support:support-v4:$rootProject.ext.supportVersion"
|
||||
implementation "com.android.support:recyclerview-v7:$rootProject.ext.supportVersion"
|
||||
implementation "com.android.support:cardview-v7:$rootProject.ext.supportVersion"
|
||||
implementation "com.android.support:swiperefreshlayout:$rootProject.ext.supportVersion"
|
||||
implementation 'androidx.core:core:1.3.2'
|
||||
implementation 'androidx.appcompat:appcompat:1.2.0'
|
||||
implementation 'com.google.android.material:material:1.3.0-alpha03'
|
||||
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
|
||||
implementation 'androidx.recyclerview:recyclerview:1.1.0'
|
||||
implementation 'androidx.cardview:cardview:1.0.0'
|
||||
implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.2.0-alpha01'
|
||||
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
|
||||
|
||||
implementation 'me.dm7.barcodescanner:zxing:1.9.8'
|
||||
implementation "com.squareup.okhttp3:okhttp:4.9.0"
|
||||
implementation "com.burgstaller:okhttp-digest:2.1"
|
||||
implementation "com.jakewharton.timber:timber:4.7.1"
|
||||
|
||||
implementation "com.squareup.okhttp3:okhttp:$rootProject.ext.okHttpVersion"
|
||||
implementation "com.burgstaller:okhttp-digest:1.18"
|
||||
implementation "com.jakewharton.timber:timber:$rootProject.ext.timberVersion"
|
||||
implementation 'com.nulab-inc:zxcvbn:1.3.0'
|
||||
|
||||
implementation 'com.nulab-inc:zxcvbn:1.2.3'
|
||||
implementation 'dnsjava:dnsjava:2.1.9'
|
||||
implementation 'org.jitsi:dnssecjava:1.2.0'
|
||||
implementation 'org.slf4j:slf4j-nop:1.7.30'
|
||||
implementation 'com.github.brnunes:swipeablerecyclerview:1.0.2'
|
||||
|
||||
implementation 'dnsjava:dnsjava:2.1.8'
|
||||
implementation 'org.jitsi:dnssecjava:1.1.3'
|
||||
implementation 'org.slf4j:slf4j-nop:1.7.25'
|
||||
implementation 'com.github.aelstad:keccakj:1.1.0'
|
||||
|
||||
testImplementation "junit:junit:$rootProject.ext.junitVersion"
|
||||
testImplementation "org.mockito:mockito-all:$rootProject.ext.mockitoVersion"
|
||||
testImplementation "com.squareup.okhttp3:mockwebserver:$rootProject.ext.okHttpVersion"
|
||||
testImplementation 'org.json:json:20140107'
|
||||
testImplementation 'net.jodah:concurrentunit:0.4.2'
|
||||
testImplementation "com.squareup.okhttp3:mockwebserver:4.9.0"
|
||||
testImplementation 'org.json:json:20180813'
|
||||
testImplementation 'net.jodah:concurrentunit:0.4.4'
|
||||
|
||||
compileOnly 'org.projectlombok:lombok:1.18.16'
|
||||
annotationProcessor 'org.projectlombok:lombok:1.18.16'
|
||||
}
|
||||
|
@@ -20,37 +20,72 @@
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/MyMaterialTheme"
|
||||
android:usesCleartextTraffic="true">
|
||||
|
||||
<activity
|
||||
android:name=".WalletActivity"
|
||||
android:configChanges="orientation|keyboardHidden"
|
||||
android:label="@string/wallet_activity_name"
|
||||
android:launchMode="singleTask"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name=".LoginActivity"
|
||||
android:configChanges="orientation|keyboardHidden"
|
||||
android:label="@string/app_name"
|
||||
android:name=".MainActivity"
|
||||
android:configChanges="orientation|keyboardHidden|uiMode"
|
||||
android:launchMode="singleTop"
|
||||
android:screenOrientation="portrait">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".WalletActivity"
|
||||
android:configChanges="orientation|keyboardHidden|uiMode"
|
||||
android:label="@string/wallet_activity_name"
|
||||
android:launchMode="singleTask"
|
||||
android:screenOrientation="behind"/>
|
||||
<activity
|
||||
android:name=".LoginActivity"
|
||||
android:configChanges="orientation|keyboardHidden|uiMode"
|
||||
android:label="@string/app_name"
|
||||
android:launchMode="singleTop"
|
||||
android:screenOrientation="locked">
|
||||
<intent-filter>
|
||||
<action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
|
||||
</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
|
||||
android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
|
||||
android:resource="@xml/usb_device_filter" />
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".onboarding.OnBoardingActivity"
|
||||
android:configChanges="orientation|keyboardHidden|uiMode"
|
||||
android:launchMode="singleTask"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<service
|
||||
android:name=".service.WalletService"
|
||||
android:description="@string/service_description"
|
||||
android:exported="false"
|
||||
android:label="Monero Wallet Service" />
|
||||
|
||||
<provider
|
||||
android:name="androidx.core.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>
|
||||
</manifest>
|
||||
</manifest>
|
||||
|
@@ -43,6 +43,9 @@ Copyright (c) 2014 Dushyanth Maguluru
|
||||
<h3>AndroidLicensesPage (https://github.com/adamsp/AndroidLicensesPage)</h3>
|
||||
Copyright (c) 2013 Adam Speakman
|
||||
|
||||
<h3>SwipeableRecyclerView (https://github.com/brnunes/SwipeableRecyclerView)</h3>
|
||||
Copyright (c) 2015 Bruno R. Nunes
|
||||
|
||||
<h3>Apache License, Version 2.0, January 2004</h3>
|
||||
http://www.apache.org/licenses/<br/>
|
||||
<br/>
|
||||
|
@@ -1,88 +0,0 @@
|
||||
// Copyright (c) 2017-2018, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
#if defined(HAVE_MONERUJO)
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief LedgerFind - find Ledger Device and return it's name
|
||||
* @param buffer - buffer for name of found device
|
||||
* @param len - length of buffer
|
||||
* @return 0 - success
|
||||
* -1 - no device connected / found
|
||||
* -2 - JVM not found
|
||||
*/
|
||||
int LedgerFind(char *buffer, size_t len);
|
||||
|
||||
/**
|
||||
* @brief LedgerExchange - exchange data with Ledger Device
|
||||
* @param command - buffer for data to send
|
||||
* @param cmd_len - length of send to send
|
||||
* @param response - buffer for received data
|
||||
* @param max_resp_len - size of receive buffer
|
||||
*
|
||||
* @return length of received data in response or -1 if error
|
||||
*/
|
||||
int LedgerExchange(unsigned char *command, unsigned int cmd_len, unsigned char *response, unsigned int max_resp_len);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#include "device_io.hpp"
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace hw {
|
||||
namespace io {
|
||||
class device_io_monerujo: device_io {
|
||||
public:
|
||||
device_io_monerujo() {};
|
||||
~device_io_monerujo() {};
|
||||
|
||||
void init() {};
|
||||
void release() {};
|
||||
|
||||
void connect(void *params) {};
|
||||
void disconnect() {};
|
||||
bool connected() const {return true;}; // monerujo is always connected before it gets here
|
||||
|
||||
// returns number of bytes read or -1 on error
|
||||
int exchange(unsigned char *command, unsigned int cmd_len, unsigned char *response, unsigned int max_resp_len) {
|
||||
return LedgerExchange(command, cmd_len, response, max_resp_len);
|
||||
}
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
#endif //#if defined(HAVE_MONERUJO)
|
File diff suppressed because it is too large
Load Diff
@@ -54,20 +54,22 @@ extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
extern const char* const MONERO_VERSION; // the actual monero core version
|
||||
|
||||
// from monero-core crypto/hash-ops.h - avoid #including monero code here
|
||||
enum {
|
||||
HASH_SIZE = 32,
|
||||
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) {
|
||||
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) {
|
||||
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
|
||||
|
@@ -46,8 +46,12 @@ public class BTChipTransportAndroidHID implements BTChipTransport {
|
||||
HashMap<String, UsbDevice> deviceList = manager.getDeviceList();
|
||||
for (UsbDevice device : deviceList.values()) {
|
||||
Timber.d("%04X:%04X %s, %s", device.getVendorId(), device.getProductId(), device.getManufacturerName(), device.getProductName());
|
||||
if ((device.getVendorId() == VID) && (device.getProductId() == PID_HID)) {
|
||||
return device;
|
||||
if (device.getVendorId() == VID) {
|
||||
final int deviceProductId = device.getProductId();
|
||||
for (int pid : PID_HIDS) {
|
||||
if (deviceProductId == pid)
|
||||
return device;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
@@ -74,7 +78,7 @@ public class BTChipTransportAndroidHID implements BTChipTransport {
|
||||
}
|
||||
|
||||
private static final int VID = 0x2C97;
|
||||
private static final int PID_HID = 0x0001;
|
||||
private static final int[] PID_HIDS = {0x0001, 0x0004};
|
||||
|
||||
private UsbDeviceConnection connection;
|
||||
private UsbInterface dongleInterface;
|
||||
|
@@ -185,7 +185,6 @@ public class Dispatcher implements PeerRetriever.OnGetPeers {
|
||||
|
||||
public void seedPeers(Collection<NodeInfo> seedNodes) {
|
||||
for (NodeInfo node : seedNodes) {
|
||||
node.clear();
|
||||
if (node.isFavourite()) {
|
||||
rpcNodes.add(node);
|
||||
if (listener != null) listener.onGet(node);
|
||||
|
@@ -173,10 +173,10 @@ public class LevinReader {
|
||||
|
||||
// this should be in LittleEndianDataInputStream because it has little
|
||||
// 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;
|
||||
for (int i = 0; i < bytes; i++) {
|
||||
result = result + (in.readUnsignedByte() << 8);
|
||||
for (int i = 1; i < bytes + 1; i++) {
|
||||
result = result + (((long) in.readUnsignedByte()) << (8 * i));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@@ -15,9 +15,9 @@ import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.os.PowerManager;
|
||||
import android.support.annotation.CallSuper;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.app.Fragment;
|
||||
import androidx.annotation.CallSuper;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.m2049r.xmrwallet.data.BarcodeData;
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -16,14 +16,10 @@
|
||||
|
||||
package com.m2049r.xmrwallet;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.design.widget.TextInputLayout;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.text.Editable;
|
||||
import android.text.Html;
|
||||
import android.text.TextWatcher;
|
||||
@@ -33,16 +29,24 @@ import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.WindowManager;
|
||||
import android.view.inputmethod.EditorInfo;
|
||||
import android.widget.Button;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.ScrollView;
|
||||
import android.widget.Switch;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
import com.google.android.material.switchmaterial.SwitchMaterial;
|
||||
import com.google.android.material.textfield.TextInputLayout;
|
||||
import com.m2049r.xmrwallet.ledger.Ledger;
|
||||
import com.m2049r.xmrwallet.ledger.LedgerProgressDialog;
|
||||
import com.m2049r.xmrwallet.model.NetworkType;
|
||||
@@ -54,6 +58,8 @@ import com.m2049r.xmrwallet.util.KeyStoreHelper;
|
||||
import com.m2049r.xmrwallet.util.MoneroThreadPoolExecutor;
|
||||
import com.m2049r.xmrwallet.widget.Toolbar;
|
||||
|
||||
import java.text.NumberFormat;
|
||||
|
||||
import timber.log.Timber;
|
||||
|
||||
public class GenerateReviewFragment extends Fragment {
|
||||
@@ -71,6 +77,7 @@ public class GenerateReviewFragment extends Fragment {
|
||||
private TextView tvWalletPassword;
|
||||
private TextView tvWalletAddress;
|
||||
private TextView tvWalletMnemonic;
|
||||
private TextView tvWalletHeight;
|
||||
private TextView tvWalletViewKey;
|
||||
private TextView tvWalletSpendKey;
|
||||
private ImageButton bCopyAddress;
|
||||
@@ -98,6 +105,7 @@ public class GenerateReviewFragment extends Fragment {
|
||||
tvWalletViewKey = view.findViewById(R.id.tvWalletViewKey);
|
||||
tvWalletSpendKey = view.findViewById(R.id.tvWalletSpendKey);
|
||||
tvWalletMnemonic = view.findViewById(R.id.tvWalletMnemonic);
|
||||
tvWalletHeight = view.findViewById(R.id.tvWalletHeight);
|
||||
bCopyAddress = view.findViewById(R.id.bCopyAddress);
|
||||
bAdvancedInfo = view.findViewById(R.id.bAdvancedInfo);
|
||||
llAdvancedInfo = view.findViewById(R.id.llAdvancedInfo);
|
||||
@@ -113,31 +121,11 @@ public class GenerateReviewFragment extends Fragment {
|
||||
tvWalletSpendKey.setTextIsSelectable(allowCopy);
|
||||
tvWalletPassword.setTextIsSelectable(allowCopy);
|
||||
|
||||
bAccept.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
acceptWallet();
|
||||
}
|
||||
});
|
||||
view.findViewById(R.id.bCopyViewKey).setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
copyViewKey();
|
||||
}
|
||||
});
|
||||
bCopyAddress.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
copyAddress();
|
||||
}
|
||||
});
|
||||
bCopyAddress.setClickable(false);
|
||||
view.findViewById(R.id.bAdvancedInfo).setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
showAdvancedInfo();
|
||||
}
|
||||
});
|
||||
bAccept.setOnClickListener(v -> acceptWallet());
|
||||
view.findViewById(R.id.bCopyViewKey).setOnClickListener(v -> copyViewKey());
|
||||
bCopyAddress.setEnabled(false);
|
||||
bCopyAddress.setOnClickListener(v -> copyAddress());
|
||||
view.findViewById(R.id.bAdvancedInfo).setOnClickListener(v -> showAdvancedInfo());
|
||||
|
||||
Bundle args = getArguments();
|
||||
type = args.getString(REQUEST_TYPE);
|
||||
@@ -187,11 +175,12 @@ public class GenerateReviewFragment extends Fragment {
|
||||
private class AsyncShow extends AsyncTask<String, Void, Boolean> {
|
||||
String name;
|
||||
String address;
|
||||
long height;
|
||||
String seed;
|
||||
String viewKey;
|
||||
String spendKey;
|
||||
boolean isWatchOnly;
|
||||
Wallet.Status status;
|
||||
Wallet.Status walletStatus;
|
||||
|
||||
boolean dialogOpened = false;
|
||||
|
||||
@@ -223,14 +212,15 @@ public class GenerateReviewFragment extends Fragment {
|
||||
closeWallet = true;
|
||||
}
|
||||
name = wallet.getName();
|
||||
status = wallet.getStatus();
|
||||
if (status != Wallet.Status.Status_Ok) {
|
||||
Timber.e(wallet.getErrorString());
|
||||
walletStatus = wallet.getStatus();
|
||||
if (!walletStatus.isOk()) {
|
||||
Timber.e(walletStatus.getErrorString());
|
||||
if (closeWallet) wallet.close();
|
||||
return false;
|
||||
}
|
||||
|
||||
address = wallet.getAddress();
|
||||
height = wallet.getRestoreHeight();
|
||||
seed = wallet.getSeed();
|
||||
switch (wallet.getDeviceType()) {
|
||||
case Device_Ledger:
|
||||
@@ -263,6 +253,7 @@ public class GenerateReviewFragment extends Fragment {
|
||||
llPassword.setVisibility(View.VISIBLE);
|
||||
tvWalletPassword.setText(getPassword());
|
||||
tvWalletAddress.setText(address);
|
||||
tvWalletHeight.setText(NumberFormat.getInstance().format(height));
|
||||
if (!seed.isEmpty()) {
|
||||
llMnemonic.setVisibility(View.VISIBLE);
|
||||
tvWalletMnemonic.setText(seed);
|
||||
@@ -279,17 +270,17 @@ public class GenerateReviewFragment extends Fragment {
|
||||
showAdvanced = true;
|
||||
}
|
||||
if (showAdvanced) bAdvancedInfo.setVisibility(View.VISIBLE);
|
||||
bCopyAddress.setClickable(true);
|
||||
bCopyAddress.setImageResource(R.drawable.ic_content_copy_black_24dp);
|
||||
bCopyAddress.setEnabled(true);
|
||||
activityCallback.setTitle(name, getString(R.string.details_title));
|
||||
activityCallback.setToolbarButton(
|
||||
GenerateReviewFragment.VIEW_TYPE_ACCEPT.equals(type) ? Toolbar.BUTTON_NONE : Toolbar.BUTTON_BACK);
|
||||
} else {
|
||||
// TODO show proper error message and/or end the fragment?
|
||||
tvWalletAddress.setText(status.toString());
|
||||
tvWalletMnemonic.setText(status.toString());
|
||||
tvWalletViewKey.setText(status.toString());
|
||||
tvWalletSpendKey.setText(status.toString());
|
||||
tvWalletAddress.setText(walletStatus.toString());
|
||||
tvWalletHeight.setText(walletStatus.toString());
|
||||
tvWalletMnemonic.setText(walletStatus.toString());
|
||||
tvWalletViewKey.setText(walletStatus.toString());
|
||||
tvWalletSpendKey.setText(walletStatus.toString());
|
||||
}
|
||||
hideProgress();
|
||||
}
|
||||
@@ -343,7 +334,7 @@ public class GenerateReviewFragment extends Fragment {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttach(Context context) {
|
||||
public void onAttach(@NonNull Context context) {
|
||||
super.onAttach(context);
|
||||
if (context instanceof Listener) {
|
||||
this.activityCallback = (Listener) context;
|
||||
@@ -390,7 +381,7 @@ public class GenerateReviewFragment extends Fragment {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
||||
public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) {
|
||||
String type = getArguments().getString(REQUEST_TYPE); // intance variable <type> not set yet
|
||||
if (GenerateReviewFragment.VIEW_TYPE_ACCEPT.equals(type)) {
|
||||
inflater.inflate(R.menu.wallet_details_help_menu, menu);
|
||||
@@ -413,12 +404,13 @@ public class GenerateReviewFragment extends Fragment {
|
||||
}
|
||||
|
||||
boolean ok = false;
|
||||
if (wallet.getStatus() == Wallet.Status.Status_Ok) {
|
||||
Wallet.Status walletStatus = wallet.getStatus();
|
||||
if (walletStatus.isOk()) {
|
||||
wallet.setPassword(newPassword);
|
||||
wallet.store();
|
||||
ok = true;
|
||||
} else {
|
||||
Timber.e(wallet.getErrorString());
|
||||
Timber.e(walletStatus.getErrorString());
|
||||
}
|
||||
if (closeWallet) wallet.close();
|
||||
return ok;
|
||||
@@ -438,7 +430,7 @@ public class GenerateReviewFragment extends Fragment {
|
||||
protected Boolean doInBackground(String... params) {
|
||||
if (params.length != 2) return false;
|
||||
final String userPassword = params[0];
|
||||
final boolean fingerPassValid = Boolean.valueOf(params[1]);
|
||||
final boolean fingerPassValid = Boolean.parseBoolean(params[1]);
|
||||
newPassword = KeyStoreHelper.getCrazyPass(getActivity(), userPassword);
|
||||
final boolean success = changeWalletPassword(newPassword);
|
||||
if (success) {
|
||||
@@ -478,7 +470,7 @@ public class GenerateReviewFragment extends Fragment {
|
||||
LayoutInflater li = LayoutInflater.from(getActivity());
|
||||
View promptsView = li.inflate(R.layout.prompt_changepw, null);
|
||||
|
||||
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(getActivity());
|
||||
AlertDialog.Builder alertDialogBuilder = new MaterialAlertDialogBuilder(getActivity());
|
||||
alertDialogBuilder.setView(promptsView);
|
||||
|
||||
final TextInputLayout etPasswordA = promptsView.findViewById(R.id.etWalletPasswordA);
|
||||
@@ -488,7 +480,7 @@ public class GenerateReviewFragment extends Fragment {
|
||||
etPasswordB.setHint(getString(R.string.prompt_changepwB, walletName));
|
||||
|
||||
LinearLayout llFingerprintAuth = promptsView.findViewById(R.id.llFingerprintAuth);
|
||||
final Switch swFingerprintAllowed = (Switch) llFingerprintAuth.getChildAt(0);
|
||||
final SwitchMaterial swFingerprintAllowed = (SwitchMaterial) llFingerprintAuth.getChildAt(0);
|
||||
if (FingerprintHelper.isDeviceSupported(getActivity())) {
|
||||
llFingerprintAuth.setVisibility(View.VISIBLE);
|
||||
|
||||
@@ -497,7 +489,7 @@ public class GenerateReviewFragment extends Fragment {
|
||||
public void onClick(View view) {
|
||||
if (!swFingerprintAllowed.isChecked()) return;
|
||||
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
|
||||
AlertDialog.Builder builder = new MaterialAlertDialogBuilder(getActivity());
|
||||
builder.setMessage(Html.fromHtml(getString(R.string.generate_fingerprint_warn)))
|
||||
.setCancelable(false)
|
||||
.setPositiveButton(getString(R.string.label_ok), null)
|
||||
@@ -586,7 +578,7 @@ public class GenerateReviewFragment extends Fragment {
|
||||
etPasswordA.setError(getString(R.string.generate_empty_passwordB));
|
||||
} else if (!newPasswordA.equals(newPasswordB)) {
|
||||
etPasswordB.setError(getString(R.string.generate_bad_passwordB));
|
||||
} else if (newPasswordA.equals(newPasswordB)) {
|
||||
} else {
|
||||
new AsyncChangePassword().execute(newPasswordA, Boolean.toString(swFingerprintAllowed.isChecked()));
|
||||
Helper.hideKeyboardAlways(getActivity());
|
||||
openDialog.dismiss();
|
||||
@@ -609,7 +601,7 @@ public class GenerateReviewFragment extends Fragment {
|
||||
etPasswordA.setError(getString(R.string.generate_empty_passwordB));
|
||||
} else if (!newPasswordA.equals(newPasswordB)) {
|
||||
etPasswordB.setError(getString(R.string.generate_bad_passwordB));
|
||||
} else if (newPasswordA.equals(newPasswordB)) {
|
||||
} else {
|
||||
new AsyncChangePassword().execute(newPasswordA, Boolean.toString(swFingerprintAllowed.isChecked()));
|
||||
Helper.hideKeyboardAlways(getActivity());
|
||||
openDialog.dismiss();
|
||||
@@ -620,6 +612,11 @@ public class GenerateReviewFragment extends Fragment {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
if (Helper.preventScreenshot()) {
|
||||
openDialog.getWindow().setFlags(WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE);
|
||||
}
|
||||
|
||||
return openDialog;
|
||||
}
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -19,11 +19,6 @@ package com.m2049r.xmrwallet;
|
||||
import android.content.Context;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.design.widget.FloatingActionButton;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
@@ -38,12 +33,19 @@ import android.widget.RelativeLayout;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
||||
import com.m2049r.xmrwallet.data.NodeInfo;
|
||||
import com.m2049r.xmrwallet.layout.NodeInfoAdapter;
|
||||
import com.m2049r.xmrwallet.layout.WalletInfoAdapter;
|
||||
import com.m2049r.xmrwallet.model.WalletManager;
|
||||
import com.m2049r.xmrwallet.util.Helper;
|
||||
import com.m2049r.xmrwallet.util.KeyStoreHelper;
|
||||
import com.m2049r.xmrwallet.util.NodePinger;
|
||||
import com.m2049r.xmrwallet.util.Notice;
|
||||
import com.m2049r.xmrwallet.widget.Toolbar;
|
||||
|
||||
@@ -63,6 +65,7 @@ public class LoginFragment extends Fragment implements WalletInfoAdapter.OnInter
|
||||
private List<WalletManager.WalletInfo> walletList = new ArrayList<>();
|
||||
private List<WalletManager.WalletInfo> displayedList = new ArrayList<>();
|
||||
|
||||
private View tvGuntherSays;
|
||||
private ImageView ivGunther;
|
||||
private TextView tvNodeName;
|
||||
private TextView tvNodeAddress;
|
||||
@@ -103,6 +106,8 @@ public class LoginFragment extends Fragment implements WalletInfoAdapter.OnInter
|
||||
|
||||
Set<NodeInfo> getFavouriteNodes();
|
||||
|
||||
Set<NodeInfo> getOrPopulateFavourites();
|
||||
|
||||
boolean hasLedger();
|
||||
}
|
||||
|
||||
@@ -130,11 +135,7 @@ public class LoginFragment extends Fragment implements WalletInfoAdapter.OnInter
|
||||
activityCallback.setTitle(null);
|
||||
activityCallback.setToolbarButton(Toolbar.BUTTON_CREDITS);
|
||||
activityCallback.showNet();
|
||||
NodeInfo node = activityCallback.getNode();
|
||||
if (node == null)
|
||||
findBestNode();
|
||||
else
|
||||
showNode(node);
|
||||
pingSelectedNode();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -143,6 +144,7 @@ public class LoginFragment extends Fragment implements WalletInfoAdapter.OnInter
|
||||
Timber.d("onCreateView");
|
||||
View view = inflater.inflate(R.layout.fragment_login, container, false);
|
||||
|
||||
tvGuntherSays = view.findViewById(R.id.tvGuntherSays);
|
||||
ivGunther = view.findViewById(R.id.ivGunther);
|
||||
fabScreen = view.findViewById(R.id.fabScreen);
|
||||
fab = view.findViewById(R.id.fab);
|
||||
@@ -183,23 +185,10 @@ public class LoginFragment extends Fragment implements WalletInfoAdapter.OnInter
|
||||
|
||||
pbNode = view.findViewById(R.id.pbNode);
|
||||
llNode = view.findViewById(R.id.llNode);
|
||||
llNode.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
if (activityCallback.getFavouriteNodes().isEmpty())
|
||||
startNodePrefs();
|
||||
else
|
||||
findBestNode();
|
||||
}
|
||||
});
|
||||
llNode.setOnClickListener(v -> startNodePrefs());
|
||||
tvNodeName = view.findViewById(R.id.tvNodeName);
|
||||
tvNodeAddress = view.findViewById(R.id.tvNodeAddress);
|
||||
view.findViewById(R.id.ibOption).setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
startNodePrefs();
|
||||
}
|
||||
});
|
||||
view.findViewById(R.id.ibRenew).setOnClickListener(v -> findBestNode());
|
||||
|
||||
Helper.hideKeyboard(getActivity());
|
||||
|
||||
@@ -275,13 +264,15 @@ public class LoginFragment extends Fragment implements WalletInfoAdapter.OnInter
|
||||
if (displayedList.isEmpty()) {
|
||||
fab.startAnimation(fab_pulse);
|
||||
if (ivGunther.getDrawable() == null) {
|
||||
ivGunther.setImageResource(R.drawable.gunther_desaturated);
|
||||
ivGunther.setImageResource(R.drawable.ic_emptygunther);
|
||||
tvGuntherSays.setVisibility(View.VISIBLE);
|
||||
}
|
||||
} else {
|
||||
fab.clearAnimation();
|
||||
if (ivGunther.getDrawable() != null) {
|
||||
ivGunther.setImageDrawable(null);
|
||||
}
|
||||
tvGuntherSays.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
// remove information of non-existent wallet
|
||||
@@ -416,33 +407,61 @@ public class LoginFragment extends Fragment implements WalletInfoAdapter.OnInter
|
||||
}
|
||||
|
||||
public void findBestNode() {
|
||||
new AsyncFindBestNode().execute();
|
||||
new AsyncFindBestNode().execute(AsyncFindBestNode.FIND_BEST);
|
||||
}
|
||||
|
||||
private class AsyncFindBestNode extends AsyncTask<Void, Void, NodeInfo> {
|
||||
public void pingSelectedNode() {
|
||||
new AsyncFindBestNode().execute(AsyncFindBestNode.PING_SELECTED);
|
||||
}
|
||||
|
||||
private NodeInfo autoselect(Set<NodeInfo> nodes) {
|
||||
if (nodes.isEmpty()) return null;
|
||||
NodePinger.execute(nodes, null);
|
||||
List<NodeInfo> nodeList = new ArrayList<>(nodes);
|
||||
Collections.sort(nodeList, NodeInfo.BestNodeComparator);
|
||||
return nodeList.get(0);
|
||||
}
|
||||
|
||||
private class AsyncFindBestNode extends AsyncTask<Integer, Void, NodeInfo> {
|
||||
final static int PING_SELECTED = 0;
|
||||
final static int FIND_BEST = 1;
|
||||
|
||||
@Override
|
||||
protected void onPreExecute() {
|
||||
super.onPreExecute();
|
||||
pbNode.setVisibility(View.VISIBLE);
|
||||
llNode.setVisibility(View.INVISIBLE);
|
||||
activityCallback.setNode(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected NodeInfo doInBackground(Void... params) {
|
||||
List<NodeInfo> nodesToTest = new ArrayList<>(activityCallback.getFavouriteNodes());
|
||||
Timber.d("testing best node from %d", nodesToTest.size());
|
||||
if (nodesToTest.isEmpty()) return null;
|
||||
for (NodeInfo node : nodesToTest) {
|
||||
node.testRpcService(); // TODO: do this in parallel?
|
||||
// no: it's better if it looks like it's doing something
|
||||
}
|
||||
Collections.sort(nodesToTest, NodeInfo.BestNodeComparator);
|
||||
NodeInfo bestNode = nodesToTest.get(0);
|
||||
if (bestNode.isValid())
|
||||
return nodesToTest.get(0);
|
||||
else
|
||||
protected NodeInfo doInBackground(Integer... params) {
|
||||
Set<NodeInfo> favourites = activityCallback.getOrPopulateFavourites();
|
||||
NodeInfo selectedNode;
|
||||
if (params[0] == FIND_BEST) {
|
||||
selectedNode = autoselect(favourites);
|
||||
} else if (params[0] == PING_SELECTED) {
|
||||
selectedNode = activityCallback.getNode();
|
||||
if (!activityCallback.getFavouriteNodes().contains(selectedNode))
|
||||
selectedNode = null; // it's not in the favourites (any longer)
|
||||
if (selectedNode == null)
|
||||
for (NodeInfo node : favourites) {
|
||||
if (node.isSelected()) {
|
||||
selectedNode = node;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (selectedNode == null) { // autoselect
|
||||
selectedNode = autoselect(favourites);
|
||||
} else
|
||||
selectedNode.testRpcService();
|
||||
} else throw new IllegalStateException();
|
||||
if ((selectedNode != null) && selectedNode.isValid()) {
|
||||
activityCallback.setNode(selectedNode);
|
||||
return selectedNode;
|
||||
} else {
|
||||
activityCallback.setNode(null);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -450,22 +469,14 @@ public class LoginFragment extends Fragment implements WalletInfoAdapter.OnInter
|
||||
if (!isAdded()) return;
|
||||
pbNode.setVisibility(View.INVISIBLE);
|
||||
llNode.setVisibility(View.VISIBLE);
|
||||
activityCallback.setNode(result);
|
||||
if (result != null) {
|
||||
Timber.d("found a good node %s", result.toString());
|
||||
showNode(result);
|
||||
} else {
|
||||
if (!activityCallback.getFavouriteNodes().isEmpty()) {
|
||||
tvNodeName.setText(getResources().getText(R.string.node_refresh_hint));
|
||||
tvNodeName.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_refresh_black_24dp, 0, 0, 0);
|
||||
tvNodeAddress.setText(null);
|
||||
tvNodeAddress.setVisibility(View.GONE);
|
||||
} else {
|
||||
tvNodeName.setText(getResources().getText(R.string.node_create_hint));
|
||||
tvNodeName.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0);
|
||||
tvNodeAddress.setText(null);
|
||||
tvNodeAddress.setVisibility(View.GONE);
|
||||
}
|
||||
tvNodeName.setText(getResources().getText(R.string.node_create_hint));
|
||||
tvNodeName.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0);
|
||||
tvNodeAddress.setText(null);
|
||||
tvNodeAddress.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -478,12 +489,11 @@ public class LoginFragment extends Fragment implements WalletInfoAdapter.OnInter
|
||||
private void showNode(NodeInfo nodeInfo) {
|
||||
tvNodeName.setText(nodeInfo.getName());
|
||||
tvNodeName.setCompoundDrawablesWithIntrinsicBounds(NodeInfoAdapter.getPingIcon(nodeInfo), 0, 0, 0);
|
||||
tvNodeAddress.setText(nodeInfo.getAddress());
|
||||
Helper.showTimeDifference(tvNodeAddress, nodeInfo.getTimestamp());
|
||||
tvNodeAddress.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
private void startNodePrefs() {
|
||||
activityCallback.setNode(null);
|
||||
activityCallback.onNodePrefs();
|
||||
}
|
||||
}
|
||||
|
39
app/src/main/java/com/m2049r/xmrwallet/MainActivity.java
Normal file
39
app/src/main/java/com/m2049r/xmrwallet/MainActivity.java
Normal file
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2020 EarlOfEgo, m2049r
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.m2049r.xmrwallet;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
import com.m2049r.xmrwallet.onboarding.OnBoardingActivity;
|
||||
import com.m2049r.xmrwallet.onboarding.OnBoardingManager;
|
||||
|
||||
public class MainActivity extends BaseActivity {
|
||||
@Override
|
||||
protected void onCreate(@Nullable final Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
if (OnBoardingManager.shouldShowOnBoarding(getApplicationContext())) {
|
||||
startActivity(new Intent(this, OnBoardingActivity.class));
|
||||
} else {
|
||||
startActivity(new Intent(this, LoginActivity.class));
|
||||
}
|
||||
finish();
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -19,7 +19,7 @@ package com.m2049r.xmrwallet;
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.support.v4.app.Fragment;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
@@ -17,12 +17,18 @@
|
||||
package com.m2049r.xmrwallet;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Configuration;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
import com.m2049r.xmrwallet.util.Helper;
|
||||
import com.m2049r.xmrwallet.util.LocaleHelper;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
import static android.view.WindowManager.LayoutParams;
|
||||
|
||||
public abstract class SecureActivity extends AppCompatActivity {
|
||||
@@ -30,14 +36,42 @@ public abstract class SecureActivity extends AppCompatActivity {
|
||||
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
// set FLAG_SECURE to prevent screenshots in Release Mode
|
||||
if (!BuildConfig.DEBUG && !BuildConfig.FLAVOR_type.equals("alpha")) {
|
||||
if (Helper.preventScreenshot()) {
|
||||
getWindow().setFlags(LayoutParams.FLAG_SECURE, LayoutParams.FLAG_SECURE);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void attachBaseContext(Context context) {
|
||||
super.attachBaseContext(LocaleHelper.setLocale(context, LocaleHelper.getLocale(context)));
|
||||
protected void attachBaseContext(Context newBase) {
|
||||
super.attachBaseContext(newBase);
|
||||
applyOverrideConfiguration(new Configuration());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyOverrideConfiguration(Configuration newConfig) {
|
||||
super.applyOverrideConfiguration(updateConfigurationIfSupported(newConfig));
|
||||
}
|
||||
|
||||
private Configuration updateConfigurationIfSupported(Configuration config) {
|
||||
// Configuration.getLocales is added after 24 and Configuration.locale is deprecated in 24
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
if (!config.getLocales().isEmpty()) {
|
||||
return config;
|
||||
}
|
||||
} else {
|
||||
if (config.locale != null) {
|
||||
return config;
|
||||
}
|
||||
}
|
||||
|
||||
Locale locale = LocaleHelper.getPreferredLocale(this);
|
||||
if (locale != null) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
|
||||
config.setLocale(locale);
|
||||
} else {
|
||||
config.locale = locale;
|
||||
}
|
||||
}
|
||||
return config;
|
||||
}
|
||||
}
|
||||
|
@@ -19,24 +19,24 @@ package com.m2049r.xmrwallet;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
import android.text.InputType;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Button;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import com.m2049r.xmrwallet.data.UserNotes;
|
||||
import com.m2049r.xmrwallet.model.TransactionInfo;
|
||||
import com.m2049r.xmrwallet.model.Transfer;
|
||||
import com.m2049r.xmrwallet.model.Wallet;
|
||||
import com.m2049r.xmrwallet.util.Helper;
|
||||
import com.m2049r.xmrwallet.util.UserNotes;
|
||||
import com.m2049r.xmrwallet.widget.Toolbar;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
@@ -71,7 +71,6 @@ public class TxFragment extends Fragment {
|
||||
private TextView tvTxFee;
|
||||
private TextView tvTxTransfers;
|
||||
private TextView etTxNotes;
|
||||
private Button bTxNotes;
|
||||
|
||||
// XMRTO stuff
|
||||
private View cvXmrTo;
|
||||
@@ -102,21 +101,9 @@ public class TxFragment extends Fragment {
|
||||
tvTxFee = view.findViewById(R.id.tvTxFee);
|
||||
tvTxTransfers = view.findViewById(R.id.tvTxTransfers);
|
||||
etTxNotes = view.findViewById(R.id.etTxNotes);
|
||||
bTxNotes = view.findViewById(R.id.bTxNotes);
|
||||
|
||||
etTxNotes.setRawInputType(InputType.TYPE_CLASS_TEXT);
|
||||
|
||||
bTxNotes.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
info.notes = null; // force reload on next view
|
||||
bTxNotes.setEnabled(false);
|
||||
etTxNotes.setEnabled(false);
|
||||
userNotes.setNote(etTxNotes.getText().toString());
|
||||
activityCallback.onSetNote(info.hash, userNotes.txNotes);
|
||||
}
|
||||
});
|
||||
|
||||
tvTxXmrToKey.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
@@ -131,14 +118,6 @@ public class TxFragment extends Fragment {
|
||||
return view;
|
||||
}
|
||||
|
||||
public void onNotesSet(boolean reload) {
|
||||
bTxNotes.setEnabled(true);
|
||||
etTxNotes.setEnabled(true);
|
||||
if (reload) {
|
||||
loadNotes(this.info);
|
||||
}
|
||||
}
|
||||
|
||||
void shareTxInfo() {
|
||||
if (this.info == null) return;
|
||||
StringBuffer sb = new StringBuffer();
|
||||
@@ -263,9 +242,9 @@ public class TxFragment extends Fragment {
|
||||
} else if (info.isPending) {
|
||||
setTxColour(ContextCompat.getColor(getContext(), R.color.tx_pending));
|
||||
} else if (info.direction == TransactionInfo.Direction.Direction_In) {
|
||||
setTxColour(ContextCompat.getColor(getContext(), R.color.tx_green));
|
||||
setTxColour(ContextCompat.getColor(getContext(), R.color.tx_plus));
|
||||
} else {
|
||||
setTxColour(ContextCompat.getColor(getContext(), R.color.tx_red));
|
||||
setTxColour(ContextCompat.getColor(getContext(), R.color.tx_minus));
|
||||
}
|
||||
Set<String> destinations = new HashSet<>();
|
||||
StringBuffer sb = new StringBuffer();
|
||||
@@ -315,7 +294,6 @@ public class TxFragment extends Fragment {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
@@ -337,9 +315,9 @@ public class TxFragment extends Fragment {
|
||||
|
||||
String getTxNotes(String hash);
|
||||
|
||||
String getTxAddress(int major, int minor);
|
||||
boolean setTxNotes(String txId, String txNotes);
|
||||
|
||||
void onSetNote(String txId, String notes);
|
||||
String getTxAddress(int major, int minor);
|
||||
|
||||
void setToolbarButton(int type);
|
||||
|
||||
@@ -357,4 +335,16 @@ public class TxFragment extends Fragment {
|
||||
+ " must implement Listener");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
if (!etTxNotes.getText().toString().equals(userNotes.note)) { // notes have changed
|
||||
// save them
|
||||
userNotes.setNote(etTxNotes.getText().toString());
|
||||
info.notes = userNotes.txNotes;
|
||||
activityCallback.setTxNotes(info.hash, info.notes);
|
||||
}
|
||||
Helper.hideKeyboard(getActivity());
|
||||
super.onPause();
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user