mirror of
https://github.com/m2049r/xmrwallet
synced 2025-04-13 10:11:11 +02:00
Merge pull request #8 from m2049r/feature_gen
Wallet Creation & Recovery
This commit is contained in:
commit
80e60bd0c8
app
.gitignoreapp.iml
src/main
cpp
java/com/m2049r/xmrwallet
GenerateFragment.javaGenerateReviewFragment.javaLoginActivity.javaLoginFragment.javaWalletActivity.javaWalletFragment.java
model
service
util
res
1
app/.gitignore
vendored
1
app/.gitignore
vendored
@ -1,2 +1,3 @@
|
|||||||
.externalNativeBuild
|
.externalNativeBuild
|
||||||
build
|
build
|
||||||
|
app.iml
|
||||||
|
147
app/app.iml
147
app/app.iml
@ -1,147 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<module external.linked.project.id=":app" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$/.." external.system.id="GRADLE" type="JAVA_MODULE" version="4">
|
|
||||||
<component name="FacetManager">
|
|
||||||
<facet type="android-gradle" name="Android-Gradle">
|
|
||||||
<configuration>
|
|
||||||
<option name="GRADLE_PROJECT_PATH" value=":app" />
|
|
||||||
</configuration>
|
|
||||||
</facet>
|
|
||||||
<facet type="native-android-gradle" name="Native-Android-Gradle">
|
|
||||||
<configuration>
|
|
||||||
<option name="SELECTED_BUILD_VARIANT" value="debug" />
|
|
||||||
</configuration>
|
|
||||||
</facet>
|
|
||||||
<facet type="android" name="Android">
|
|
||||||
<configuration>
|
|
||||||
<option name="SELECTED_BUILD_VARIANT" value="debug" />
|
|
||||||
<option name="ASSEMBLE_TASK_NAME" value="assembleDebug" />
|
|
||||||
<option name="COMPILE_JAVA_TASK_NAME" value="compileDebugSources" />
|
|
||||||
<afterSyncTasks>
|
|
||||||
<task>generateDebugSources</task>
|
|
||||||
</afterSyncTasks>
|
|
||||||
<option name="ALLOW_USER_CONFIGURATION" value="false" />
|
|
||||||
<option name="MANIFEST_FILE_RELATIVE_PATH" value="/src/main/AndroidManifest.xml" />
|
|
||||||
<option name="RES_FOLDER_RELATIVE_PATH" value="/src/main/res" />
|
|
||||||
<option name="RES_FOLDERS_RELATIVE_PATH" value="file://$MODULE_DIR$/src/main/res" />
|
|
||||||
<option name="ASSETS_FOLDER_RELATIVE_PATH" value="/src/main/assets" />
|
|
||||||
</configuration>
|
|
||||||
</facet>
|
|
||||||
</component>
|
|
||||||
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_7" inherit-compiler-output="false">
|
|
||||||
<output url="file://$MODULE_DIR$/build/intermediates/classes/debug" />
|
|
||||||
<output-test url="file://$MODULE_DIR$/build/intermediates/classes/test/debug" />
|
|
||||||
<exclude-output />
|
|
||||||
<content url="file://$MODULE_DIR$">
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/main/cpp" isTestSource="false" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/r/debug" isTestSource="false" generated="true" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/aidl/debug" isTestSource="false" generated="true" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/debug" isTestSource="false" generated="true" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/rs/debug" isTestSource="false" generated="true" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/apt/debug" isTestSource="false" generated="true" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/debug" type="java-resource" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/resValues/debug" type="java-resource" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/r/androidTest/debug" isTestSource="true" generated="true" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/aidl/androidTest/debug" isTestSource="true" generated="true" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/androidTest/debug" isTestSource="true" generated="true" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/rs/androidTest/debug" isTestSource="true" generated="true" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/apt/androidTest/debug" isTestSource="true" generated="true" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/androidTest/debug" type="java-test-resource" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/resValues/androidTest/debug" type="java-test-resource" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/res" type="java-resource" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/resources" type="java-resource" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/assets" type="java-resource" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/aidl" isTestSource="false" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/java" isTestSource="false" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/jni" isTestSource="false" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/rs" isTestSource="false" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/shaders" isTestSource="false" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/res" type="java-test-resource" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/resources" type="java-test-resource" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/assets" type="java-test-resource" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/aidl" isTestSource="true" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/java" isTestSource="true" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/jni" isTestSource="true" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/rs" isTestSource="true" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/shaders" isTestSource="true" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/main/res" type="java-resource" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/main/assets" type="java-resource" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/main/aidl" isTestSource="false" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/main/jni" isTestSource="false" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/main/rs" isTestSource="false" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/main/shaders" isTestSource="false" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/res" type="java-test-resource" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/resources" type="java-test-resource" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/assets" type="java-test-resource" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/aidl" isTestSource="true" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/java" isTestSource="true" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/jni" isTestSource="true" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/rs" isTestSource="true" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/shaders" isTestSource="true" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/test/res" type="java-test-resource" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/test/resources" type="java-test-resource" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/test/assets" type="java-test-resource" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/test/aidl" isTestSource="true" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/test/jni" isTestSource="true" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/test/rs" isTestSource="true" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/test/shaders" isTestSource="true" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/assets" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/blame" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/builds" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/classes" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/cmake" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental-classes" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental-runtime-classes" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental-safeguard" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental-verifier" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/instant-run-resources" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/instant-run-support" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/jniLibs" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/manifests" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/reload-dex" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/res" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/restart-dex" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/rs" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/shaders" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/split-apk" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/symbols" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/transforms" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/build/outputs" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/build/tmp" />
|
|
||||||
</content>
|
|
||||||
<orderEntry type="jdk" jdkName="Android API 25 Platform" jdkType="Android SDK" />
|
|
||||||
<orderEntry type="sourceFolder" forTests="false" />
|
|
||||||
<orderEntry type="library" exported="" scope="TEST" name="runner-0.5" level="project" />
|
|
||||||
<orderEntry type="library" exported="" scope="TEST" name="espresso-idling-resource-2.2.2" level="project" />
|
|
||||||
<orderEntry type="library" exported="" name="constraint-layout-1.0.2" level="project" />
|
|
||||||
<orderEntry type="library" exported="" scope="TEST" name="hamcrest-library-1.3" level="project" />
|
|
||||||
<orderEntry type="library" exported="" name="transition-25.3.1" level="project" />
|
|
||||||
<orderEntry type="library" exported="" scope="TEST" name="hamcrest-integration-1.3" level="project" />
|
|
||||||
<orderEntry type="library" exported="" name="design-25.3.1" level="project" />
|
|
||||||
<orderEntry type="library" exported="" name="support-core-ui-25.3.1" level="project" />
|
|
||||||
<orderEntry type="library" exported="" name="cardview-v7-25.3.1" level="project" />
|
|
||||||
<orderEntry type="library" exported="" scope="TEST" name="jsr305-2.0.1" level="project" />
|
|
||||||
<orderEntry type="library" exported="" name="support-core-utils-25.3.1" level="project" />
|
|
||||||
<orderEntry type="library" exported="" name="support-fragment-25.3.1" level="project" />
|
|
||||||
<orderEntry type="library" exported="" scope="TEST" name="espresso-core-2.2.2" level="project" />
|
|
||||||
<orderEntry type="library" exported="" scope="TEST" name="exposed-instrumentation-api-publish-0.5" level="project" />
|
|
||||||
<orderEntry type="library" exported="" scope="TEST" name="rules-0.5" level="project" />
|
|
||||||
<orderEntry type="library" exported="" name="constraint-layout-solver-1.0.2" level="project" />
|
|
||||||
<orderEntry type="library" exported="" scope="TEST" name="javax.annotation-api-1.2" level="project" />
|
|
||||||
<orderEntry type="library" exported="" scope="TEST" name="javax.inject-1" level="project" />
|
|
||||||
<orderEntry type="library" exported="" scope="TEST" name="javawriter-2.1.1" level="project" />
|
|
||||||
<orderEntry type="library" exported="" name="support-v4-25.3.1" level="project" />
|
|
||||||
<orderEntry type="library" exported="" name="support-media-compat-25.3.1" level="project" />
|
|
||||||
<orderEntry type="library" exported="" scope="TEST" name="hamcrest-core-1.3" level="project" />
|
|
||||||
<orderEntry type="library" exported="" scope="TEST" name="junit-4.12" level="project" />
|
|
||||||
<orderEntry type="library" exported="" name="recyclerview-v7-25.3.1" level="project" />
|
|
||||||
<orderEntry type="library" exported="" name="support-annotations-25.3.1" level="project" />
|
|
||||||
<orderEntry type="library" exported="" name="appcompat-v7-25.3.1" level="project" />
|
|
||||||
<orderEntry type="library" exported="" name="support-vector-drawable-25.3.1" level="project" />
|
|
||||||
<orderEntry type="library" exported="" name="support-compat-25.3.1" level="project" />
|
|
||||||
<orderEntry type="library" exported="" name="animated-vector-drawable-25.3.1" level="project" />
|
|
||||||
</component>
|
|
||||||
</module>
|
|
@ -302,7 +302,7 @@ Java_com_m2049r_xmrwallet_model_WalletManager_recoveryWalletJ(JNIEnv *env, jobje
|
|||||||
return reinterpret_cast<jlong>(wallet);
|
return reinterpret_cast<jlong>(wallet);
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT jboolean JNICALL
|
JNIEXPORT jlong JNICALL
|
||||||
Java_com_m2049r_xmrwallet_model_WalletManager_createWalletFromKeysJ(JNIEnv *env, jobject instance,
|
Java_com_m2049r_xmrwallet_model_WalletManager_createWalletFromKeysJ(JNIEnv *env, jobject instance,
|
||||||
jstring path, jstring language,
|
jstring path, jstring language,
|
||||||
jboolean isTestNet,
|
jboolean isTestNet,
|
||||||
@ -463,7 +463,7 @@ Java_com_m2049r_xmrwallet_model_WalletManager_resolveOpenAlias(JNIEnv *env, jobj
|
|||||||
|
|
||||||
//TODO static std::tuple<bool, std::string, std::string, std::string, std::string> checkUpdates(const std::string &software, const std::string &subdir);
|
//TODO static std::tuple<bool, std::string, std::string, std::string, std::string> checkUpdates(const std::string &software, const std::string &subdir);
|
||||||
|
|
||||||
// actually a WalletManager function, but logically in Wallet
|
// actually a WalletManager function, but logically in onWalletSelected
|
||||||
JNIEXPORT jboolean JNICALL
|
JNIEXPORT jboolean JNICALL
|
||||||
Java_com_m2049r_xmrwallet_model_WalletManager_closeJ(JNIEnv *env, jobject instance,
|
Java_com_m2049r_xmrwallet_model_WalletManager_closeJ(JNIEnv *env, jobject instance,
|
||||||
jobject walletInstance) {
|
jobject walletInstance) {
|
||||||
|
407
app/src/main/java/com/m2049r/xmrwallet/GenerateFragment.java
Normal file
407
app/src/main/java/com/m2049r/xmrwallet/GenerateFragment.java
Normal file
@ -0,0 +1,407 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2017 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.app.Fragment;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.text.Editable;
|
||||||
|
import android.text.TextWatcher;
|
||||||
|
import android.view.KeyEvent;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.view.inputmethod.EditorInfo;
|
||||||
|
import android.widget.Button;
|
||||||
|
import android.widget.EditText;
|
||||||
|
import android.widget.LinearLayout;
|
||||||
|
import android.widget.TextView;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import com.m2049r.xmrwallet.model.WalletManager;
|
||||||
|
import com.m2049r.xmrwallet.util.Helper;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
public class GenerateFragment extends Fragment {
|
||||||
|
static final String TAG = "GenerateFragment";
|
||||||
|
|
||||||
|
EditText etWalletName;
|
||||||
|
EditText etWalletPassword;
|
||||||
|
EditText etWalletAddress;
|
||||||
|
EditText etWalletMnemonic;
|
||||||
|
LinearLayout llRestoreKeys;
|
||||||
|
EditText etWalletViewKey;
|
||||||
|
EditText etWalletSpendKey;
|
||||||
|
EditText etWalletRestoreHeight;
|
||||||
|
Button bGenerate;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||||
|
Bundle savedInstanceState) {
|
||||||
|
|
||||||
|
View view = inflater.inflate(R.layout.gen_fragment, container, false);
|
||||||
|
|
||||||
|
etWalletName = (EditText) view.findViewById(R.id.etWalletName);
|
||||||
|
etWalletPassword = (EditText) view.findViewById(R.id.etWalletPassword);
|
||||||
|
etWalletMnemonic = (EditText) view.findViewById(R.id.etWalletMnemonic);
|
||||||
|
etWalletAddress = (EditText) view.findViewById(R.id.etWalletAddress);
|
||||||
|
llRestoreKeys = (LinearLayout) view.findViewById(R.id.llRestoreKeys);
|
||||||
|
etWalletViewKey = (EditText) view.findViewById(R.id.etWalletViewKey);
|
||||||
|
etWalletSpendKey = (EditText) view.findViewById(R.id.etWalletSpendKey);
|
||||||
|
etWalletRestoreHeight = (EditText) view.findViewById(R.id.etWalletRestoreHeight);
|
||||||
|
bGenerate = (Button) view.findViewById(R.id.bGenerate);
|
||||||
|
|
||||||
|
boolean testnet = WalletManager.getInstance().isTestNet();
|
||||||
|
etWalletMnemonic.setTextIsSelectable(testnet);
|
||||||
|
|
||||||
|
etWalletName.requestFocus();
|
||||||
|
Helper.showKeyboard(getActivity());
|
||||||
|
etWalletName.addTextChangedListener(new TextWatcher() {
|
||||||
|
@Override
|
||||||
|
public void afterTextChanged(Editable editable) {
|
||||||
|
if (etWalletName.length() > 0) {
|
||||||
|
bGenerate.setEnabled(true);
|
||||||
|
} else {
|
||||||
|
bGenerate.setEnabled(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
||||||
|
}
|
||||||
|
});
|
||||||
|
etWalletName.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
Helper.showKeyboard(getActivity());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
etWalletName.setOnEditorActionListener(new TextView.OnEditorActionListener() {
|
||||||
|
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
|
||||||
|
if ((event != null && (event.getKeyCode() == KeyEvent.KEYCODE_ENTER)) || (actionId == EditorInfo.IME_ACTION_NEXT)) {
|
||||||
|
if (etWalletName.length() > 0) {
|
||||||
|
etWalletPassword.requestFocus();
|
||||||
|
} // otherwise ignore
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
etWalletPassword.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
Helper.showKeyboard(getActivity());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
etWalletPassword.setOnEditorActionListener(new TextView.OnEditorActionListener() {
|
||||||
|
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
|
||||||
|
if ((event != null && (event.getKeyCode() == KeyEvent.KEYCODE_ENTER)) || (actionId == EditorInfo.IME_ACTION_NEXT)) {
|
||||||
|
if (etWalletAddress.length() > 0) {
|
||||||
|
etWalletAddress.requestFocus();
|
||||||
|
} else {
|
||||||
|
etWalletMnemonic.requestFocus();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
etWalletMnemonic.setOnEditorActionListener(new TextView.OnEditorActionListener() {
|
||||||
|
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
|
||||||
|
if ((event != null && (event.getKeyCode() == KeyEvent.KEYCODE_ENTER)) || (actionId == EditorInfo.IME_ACTION_NEXT)) {
|
||||||
|
if (etWalletMnemonic.length() == 0) {
|
||||||
|
etWalletAddress.requestFocus();
|
||||||
|
} else if (mnemonicOk()) {
|
||||||
|
etWalletRestoreHeight.requestFocus();
|
||||||
|
} else {
|
||||||
|
Toast.makeText(getActivity(), getString(R.string.generate_check_mnemonic), Toast.LENGTH_LONG).show();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
etWalletMnemonic.setOnClickListener(new View.OnClickListener()
|
||||||
|
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
Helper.showKeyboard(getActivity());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
etWalletMnemonic.addTextChangedListener(new
|
||||||
|
|
||||||
|
TextWatcher() {
|
||||||
|
@Override
|
||||||
|
public void afterTextChanged(Editable editable) {
|
||||||
|
if (etWalletMnemonic.length() > 0) {
|
||||||
|
etWalletRestoreHeight.setVisibility(View.VISIBLE);
|
||||||
|
etWalletAddress.setVisibility(View.INVISIBLE);
|
||||||
|
} else {
|
||||||
|
etWalletAddress.setVisibility(View.VISIBLE);
|
||||||
|
if (etWalletAddress.length() == 0) {
|
||||||
|
etWalletRestoreHeight.setVisibility(View.INVISIBLE);
|
||||||
|
} else {
|
||||||
|
etWalletRestoreHeight.setVisibility(View.VISIBLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
etWalletAddress.setOnEditorActionListener(new TextView.OnEditorActionListener()
|
||||||
|
|
||||||
|
{
|
||||||
|
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
|
||||||
|
if ((event != null && (event.getKeyCode() == KeyEvent.KEYCODE_ENTER)) || (actionId == EditorInfo.IME_ACTION_NEXT)) {
|
||||||
|
if (etWalletAddress.length() == 0) {
|
||||||
|
if (bGenerate.getVisibility() == View.VISIBLE) {
|
||||||
|
Helper.hideKeyboard(getActivity());
|
||||||
|
generateWallet();
|
||||||
|
}
|
||||||
|
} else if (addressOk()) {
|
||||||
|
etWalletViewKey.requestFocus();
|
||||||
|
} else {
|
||||||
|
Toast.makeText(getActivity(), getString(R.string.generate_check_address), Toast.LENGTH_LONG).show();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
etWalletAddress.setOnClickListener(new View.OnClickListener()
|
||||||
|
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
Helper.showKeyboard(getActivity());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
etWalletAddress.addTextChangedListener(new
|
||||||
|
|
||||||
|
TextWatcher() {
|
||||||
|
@Override
|
||||||
|
public void afterTextChanged(Editable editable) {
|
||||||
|
if (etWalletAddress.length() > 0) {
|
||||||
|
llRestoreKeys.setVisibility(View.VISIBLE);
|
||||||
|
etWalletMnemonic.setVisibility(View.INVISIBLE);
|
||||||
|
etWalletRestoreHeight.setVisibility(View.VISIBLE);
|
||||||
|
} else {
|
||||||
|
llRestoreKeys.setVisibility(View.INVISIBLE);
|
||||||
|
etWalletMnemonic.setVisibility(View.VISIBLE);
|
||||||
|
if (etWalletMnemonic.length() == 0) {
|
||||||
|
etWalletRestoreHeight.setVisibility(View.INVISIBLE);
|
||||||
|
} else {
|
||||||
|
etWalletRestoreHeight.setVisibility(View.VISIBLE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
etWalletViewKey.setOnEditorActionListener(new TextView.OnEditorActionListener()
|
||||||
|
|
||||||
|
{
|
||||||
|
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
|
||||||
|
if ((event != null && (event.getKeyCode() == KeyEvent.KEYCODE_ENTER)) || (actionId == EditorInfo.IME_ACTION_NEXT)) {
|
||||||
|
if (viewKeyOk()) {
|
||||||
|
etWalletSpendKey.requestFocus();
|
||||||
|
} else {
|
||||||
|
Toast.makeText(getActivity(), getString(R.string.generate_check_key), Toast.LENGTH_LONG).show();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
etWalletViewKey.setOnClickListener(new View.OnClickListener()
|
||||||
|
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
Helper.showKeyboard(getActivity());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
etWalletSpendKey.setOnEditorActionListener(new TextView.OnEditorActionListener()
|
||||||
|
|
||||||
|
{
|
||||||
|
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
|
||||||
|
if ((event != null && (event.getKeyCode() == KeyEvent.KEYCODE_ENTER)) || (actionId == EditorInfo.IME_ACTION_NEXT)) {
|
||||||
|
if (spendKeyOk()) {
|
||||||
|
etWalletRestoreHeight.requestFocus();
|
||||||
|
} else {
|
||||||
|
Toast.makeText(getActivity(), getString(R.string.generate_check_key), Toast.LENGTH_LONG).show();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
etWalletSpendKey.setOnClickListener(new View.OnClickListener()
|
||||||
|
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
Helper.showKeyboard(getActivity());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
etWalletRestoreHeight.setOnEditorActionListener(new TextView.OnEditorActionListener()
|
||||||
|
|
||||||
|
{
|
||||||
|
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
|
||||||
|
if ((event != null && (event.getKeyCode() == KeyEvent.KEYCODE_ENTER)) || (actionId == EditorInfo.IME_ACTION_NEXT)) {
|
||||||
|
if (bGenerate.getVisibility() == View.VISIBLE) {
|
||||||
|
Helper.hideKeyboard(getActivity());
|
||||||
|
generateWallet();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
bGenerate.setOnClickListener(new View.OnClickListener()
|
||||||
|
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
Helper.hideKeyboard(getActivity());
|
||||||
|
generateWallet();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean mnemonicOk() {
|
||||||
|
String seed = etWalletMnemonic.getText().toString();
|
||||||
|
return (seed.split("\\s").length == 25); // 25 words
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean addressOk() {
|
||||||
|
String address = etWalletAddress.getText().toString();
|
||||||
|
return ((address.length() == 95) && ("49A".indexOf(address.charAt(0)) >= 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean viewKeyOk() {
|
||||||
|
String viewKey = etWalletViewKey.getText().toString();
|
||||||
|
return (viewKey.length() == 64) && (viewKey.matches("^[0-9a-fA-F]+$"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean spendKeyOk() {
|
||||||
|
String spendKey = etWalletSpendKey.getText().toString();
|
||||||
|
return ((spendKey.length() == 0) || ((spendKey.length() == 64) && (spendKey.matches("^[0-9a-fA-F]+$"))));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void generateWallet() {
|
||||||
|
String name = etWalletName.getText().toString();
|
||||||
|
if (name.length() == 0) return;
|
||||||
|
String walletPath = Helper.getWalletPath(getActivity(), name);
|
||||||
|
if (WalletManager.getInstance().walletExists(walletPath)) {
|
||||||
|
Toast.makeText(getActivity(), getString(R.string.generate_wallet_exists), Toast.LENGTH_LONG).show();
|
||||||
|
etWalletName.requestFocus();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String password = etWalletPassword.getText().toString();
|
||||||
|
|
||||||
|
String seed = etWalletMnemonic.getText().toString();
|
||||||
|
String address = etWalletAddress.getText().toString();
|
||||||
|
|
||||||
|
long height;
|
||||||
|
try {
|
||||||
|
height = Long.parseLong(etWalletRestoreHeight.getText().toString());
|
||||||
|
} catch (NumberFormatException ex) {
|
||||||
|
height = 0; // Keep calm and carry on!
|
||||||
|
}
|
||||||
|
|
||||||
|
// figure out how we want to create this wallet
|
||||||
|
// A. from scratch
|
||||||
|
if ((seed.length() == 0) && (address.length() == 0)) {
|
||||||
|
bGenerate.setVisibility(View.INVISIBLE);
|
||||||
|
activityCallback.onGenerate(name, password);
|
||||||
|
} else
|
||||||
|
// B. from seed
|
||||||
|
if (mnemonicOk()) {
|
||||||
|
bGenerate.setVisibility(View.INVISIBLE);
|
||||||
|
activityCallback.onGenerate(name, password, seed, height);
|
||||||
|
} else
|
||||||
|
// C. from keys
|
||||||
|
if (addressOk() && viewKeyOk() && (spendKeyOk())) {
|
||||||
|
String viewKey = etWalletViewKey.getText().toString();
|
||||||
|
String spendKey = etWalletSpendKey.getText().toString();
|
||||||
|
bGenerate.setVisibility(View.INVISIBLE);
|
||||||
|
activityCallback.onGenerate(name, password, address, viewKey, spendKey, height);
|
||||||
|
} else
|
||||||
|
// D. none of the above :)
|
||||||
|
{
|
||||||
|
Toast.makeText(getActivity(), getString(R.string.generate_check_something), Toast.LENGTH_LONG).show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void walletGenerateError() {
|
||||||
|
bGenerate.setEnabled(etWalletName.length() > 0);
|
||||||
|
bGenerate.setVisibility(View.VISIBLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
GenerateFragment.Listener activityCallback;
|
||||||
|
|
||||||
|
public interface Listener {
|
||||||
|
void onGenerate(String name, String password);
|
||||||
|
|
||||||
|
void onGenerate(String name, String password, String seed, long height);
|
||||||
|
|
||||||
|
void onGenerate(String name, String password, String address, String viewKey, String spendKey, long height);
|
||||||
|
|
||||||
|
File getStorageRoot();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAttach(Context context) {
|
||||||
|
super.onAttach(context);
|
||||||
|
if (context instanceof GenerateFragment.Listener) {
|
||||||
|
this.activityCallback = (GenerateFragment.Listener) context;
|
||||||
|
} else {
|
||||||
|
throw new ClassCastException(context.toString()
|
||||||
|
+ " must implement Listener");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,115 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2017 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.app.Fragment;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.Button;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import com.m2049r.xmrwallet.model.WalletManager;
|
||||||
|
|
||||||
|
public class GenerateReviewFragment extends Fragment {
|
||||||
|
static final String TAG = "GenerateReviewFragment";
|
||||||
|
|
||||||
|
TextView tvWalletName;
|
||||||
|
TextView tvWalletPassword;
|
||||||
|
TextView tvWalletAddress;
|
||||||
|
TextView tvWalletMnemonic;
|
||||||
|
TextView tvWalletViewKey;
|
||||||
|
TextView tvWalletSpendKey;
|
||||||
|
Button bAccept;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||||
|
Bundle savedInstanceState) {
|
||||||
|
|
||||||
|
View view = inflater.inflate(R.layout.gen_review_fragment, container, false);
|
||||||
|
|
||||||
|
tvWalletName = (TextView) view.findViewById(R.id.tvWalletName);
|
||||||
|
tvWalletPassword = (TextView) view.findViewById(R.id.tvWalletPassword);
|
||||||
|
tvWalletAddress = (TextView) view.findViewById(R.id.tvWalletAddress);
|
||||||
|
tvWalletViewKey = (TextView) view.findViewById(R.id.tvWalletViewKey);
|
||||||
|
tvWalletSpendKey = (TextView) view.findViewById(R.id.tvWalletSpendKey);
|
||||||
|
tvWalletMnemonic = (TextView) view.findViewById(R.id.tvWalletMnemonic);
|
||||||
|
|
||||||
|
bAccept = (Button) view.findViewById(R.id.bAccept);
|
||||||
|
|
||||||
|
boolean testnet = WalletManager.getInstance().isTestNet();
|
||||||
|
tvWalletMnemonic.setTextIsSelectable(testnet);
|
||||||
|
|
||||||
|
bAccept.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
acceptWallet();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
showDetails();
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void acceptWallet() {
|
||||||
|
String name = tvWalletName.getText().toString();
|
||||||
|
String password = tvWalletPassword.getText().toString();
|
||||||
|
bAccept.setEnabled(false);
|
||||||
|
activityCallback.onAccept(name, password);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void showDetails() {
|
||||||
|
Bundle b = getArguments();
|
||||||
|
String name = b.getString("name");
|
||||||
|
String password = b.getString("password");
|
||||||
|
String address = b.getString("address");
|
||||||
|
String seed = b.getString("seed");
|
||||||
|
String view = b.getString("viewkey");
|
||||||
|
String spend = b.getString("spendkey");
|
||||||
|
|
||||||
|
tvWalletName.setText(name);
|
||||||
|
tvWalletPassword.setText(password);
|
||||||
|
tvWalletAddress.setText(address);
|
||||||
|
tvWalletMnemonic.setText(seed);
|
||||||
|
tvWalletViewKey.setText(view);
|
||||||
|
if (spend.length() > 0) { // should be == 64, but spendkey is not in the API yet
|
||||||
|
tvWalletSpendKey.setText(spend);
|
||||||
|
} else {
|
||||||
|
tvWalletSpendKey.setText(getString(R.string.generate_wallet_watchonly));
|
||||||
|
}
|
||||||
|
bAccept.setEnabled(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
GenerateReviewFragment.Listener activityCallback;
|
||||||
|
|
||||||
|
public interface Listener {
|
||||||
|
void onAccept(String name, String password);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAttach(Context context) {
|
||||||
|
super.onAttach(context);
|
||||||
|
if (context instanceof GenerateReviewFragment.Listener) {
|
||||||
|
this.activityCallback = (GenerateReviewFragment.Listener) context;
|
||||||
|
} else {
|
||||||
|
throw new ClassCastException(context.toString()
|
||||||
|
+ " must implement Listener");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -19,29 +19,39 @@ package com.m2049r.xmrwallet;
|
|||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.app.AlertDialog;
|
import android.app.AlertDialog;
|
||||||
import android.app.Fragment;
|
import android.app.Fragment;
|
||||||
|
import android.app.FragmentManager;
|
||||||
|
import android.app.FragmentTransaction;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.DialogInterface;
|
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.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.provider.MediaStore;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
|
import android.support.v7.app.AppCompatActivity;
|
||||||
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.View;
|
import android.view.View;
|
||||||
import android.view.WindowManager;
|
|
||||||
import android.view.inputmethod.EditorInfo;
|
import android.view.inputmethod.EditorInfo;
|
||||||
import android.widget.EditText;
|
import android.widget.EditText;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import com.m2049r.xmrwallet.model.Wallet;
|
||||||
import com.m2049r.xmrwallet.model.WalletManager;
|
import com.m2049r.xmrwallet.model.WalletManager;
|
||||||
|
import com.m2049r.xmrwallet.service.MoneroHandlerThread;
|
||||||
import com.m2049r.xmrwallet.util.Helper;
|
import com.m2049r.xmrwallet.util.Helper;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.channels.FileChannel;
|
||||||
|
|
||||||
public class LoginActivity extends Activity implements LoginFragment.LoginFragmentListener {
|
public class LoginActivity extends AppCompatActivity
|
||||||
|
implements LoginFragment.Listener, GenerateFragment.Listener, GenerateReviewFragment.Listener {
|
||||||
static final String TAG = "LoginActivity";
|
static final String TAG = "LoginActivity";
|
||||||
|
|
||||||
static final int DAEMON_TIMEOUT = 500; // deamon must respond in 500ms
|
static final int DAEMON_TIMEOUT = 500; // deamon must respond in 500ms
|
||||||
@ -60,9 +70,26 @@ public class LoginActivity extends Activity implements LoginFragment.LoginFragme
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// adapted from http://www.mkyong.com/android/android-prompt-user-input-dialog-example/
|
|
||||||
@Override
|
@Override
|
||||||
public void promptPassword(final String wallet) {
|
public void onWalletSelected(final String walletName) {
|
||||||
|
Log.d(TAG, "selected wallet is ." + walletName + ".");
|
||||||
|
if (walletName.equals(':' + getString(R.string.generate_title))) {
|
||||||
|
startGenerateFragment();
|
||||||
|
} else {
|
||||||
|
// now it's getting real, check if wallet exists
|
||||||
|
String walletPath = Helper.getWalletPath(this, walletName);
|
||||||
|
if (WalletManager.getInstance().walletExists(walletPath)) {
|
||||||
|
promptPassword(walletName);
|
||||||
|
} else { // this cannot really happen as we prefilter choices
|
||||||
|
Toast.makeText(this, getString(R.string.bad_wallet), Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AlertDialog passwordDialog = null; // for preventing multiple clicks in wallet list
|
||||||
|
|
||||||
|
void promptPassword(final String wallet) {
|
||||||
|
if (passwordDialog != null) return; // we are already asking for password
|
||||||
Context context = LoginActivity.this;
|
Context context = LoginActivity.this;
|
||||||
LayoutInflater li = LayoutInflater.from(context);
|
LayoutInflater li = LayoutInflater.from(context);
|
||||||
View promptsView = li.inflate(R.layout.prompt_password, null);
|
View promptsView = li.inflate(R.layout.prompt_password, null);
|
||||||
@ -81,37 +108,40 @@ public class LoginActivity extends Activity implements LoginFragment.LoginFragme
|
|||||||
.setPositiveButton("OK",
|
.setPositiveButton("OK",
|
||||||
new DialogInterface.OnClickListener() {
|
new DialogInterface.OnClickListener() {
|
||||||
public void onClick(DialogInterface dialog, int id) {
|
public void onClick(DialogInterface dialog, int id) {
|
||||||
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
|
Helper.hideKeyboardAlways(LoginActivity.this);
|
||||||
String pass = etPassword.getText().toString();
|
String pass = etPassword.getText().toString();
|
||||||
processPasswordEntry(wallet, pass);
|
processPasswordEntry(wallet, pass);
|
||||||
|
passwordDialog = null;
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.setNegativeButton("Cancel",
|
.setNegativeButton("Cancel",
|
||||||
new DialogInterface.OnClickListener() {
|
new DialogInterface.OnClickListener() {
|
||||||
public void onClick(DialogInterface dialog, int id) {
|
public void onClick(DialogInterface dialog, int id) {
|
||||||
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
|
Helper.hideKeyboardAlways(LoginActivity.this);
|
||||||
dialog.cancel();
|
dialog.cancel();
|
||||||
|
passwordDialog = null;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
final AlertDialog alertDialog = alertDialogBuilder.create();
|
passwordDialog = alertDialogBuilder.create();
|
||||||
// request keyboard
|
Helper.showKeyboard(passwordDialog);
|
||||||
alertDialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
|
|
||||||
// accept keyboard "ok"
|
// accept keyboard "ok"
|
||||||
etPassword.setOnEditorActionListener(new TextView.OnEditorActionListener() {
|
etPassword.setOnEditorActionListener(new TextView.OnEditorActionListener() {
|
||||||
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
|
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
|
||||||
if ((event != null && (event.getKeyCode() == KeyEvent.KEYCODE_ENTER)) || (actionId == EditorInfo.IME_ACTION_DONE)) {
|
if ((event != null && (event.getKeyCode() == KeyEvent.KEYCODE_ENTER)) || (actionId == EditorInfo.IME_ACTION_DONE)) {
|
||||||
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
|
Helper.hideKeyboardAlways(LoginActivity.this);
|
||||||
String pass = etPassword.getText().toString();
|
String pass = etPassword.getText().toString();
|
||||||
alertDialog.cancel();
|
passwordDialog.cancel();
|
||||||
processPasswordEntry(wallet, pass);
|
processPasswordEntry(wallet, pass);
|
||||||
|
passwordDialog = null;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
alertDialog.show();
|
passwordDialog.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean checkWalletPassword(String walletName, String password) {
|
private boolean checkWalletPassword(String walletName, String password) {
|
||||||
@ -130,7 +160,7 @@ public class LoginActivity extends Activity implements LoginFragment.LoginFragme
|
|||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////
|
////////////////////////////////////////
|
||||||
// LoginFragment.LoginFragmentListener
|
// LoginFragment.Listener
|
||||||
////////////////////////////////////////
|
////////////////////////////////////////
|
||||||
@Override
|
@Override
|
||||||
public SharedPreferences getPrefs() {
|
public SharedPreferences getPrefs() {
|
||||||
@ -142,6 +172,11 @@ public class LoginActivity extends Activity implements LoginFragment.LoginFragme
|
|||||||
return Helper.getStorageRoot(getApplicationContext());
|
return Helper.getStorageRoot(getApplicationContext());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setTitle(String title) {
|
||||||
|
super.setTitle(title);
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////
|
////////////////////////////////////////
|
||||||
////////////////////////////////////////
|
////////////////////////////////////////
|
||||||
|
|
||||||
@ -178,7 +213,7 @@ public class LoginActivity extends Activity implements LoginFragment.LoginFragme
|
|||||||
} else {
|
} else {
|
||||||
String msg = getString(R.string.message_strorage_not_permitted);
|
String msg = getString(R.string.message_strorage_not_permitted);
|
||||||
Log.e(TAG, msg);
|
Log.e(TAG, msg);
|
||||||
Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
|
Toast.makeText(this, msg, Toast.LENGTH_LONG).show();
|
||||||
//throw new IllegalStateException(msg);
|
//throw new IllegalStateException(msg);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -190,6 +225,209 @@ public class LoginActivity extends Activity implements LoginFragment.LoginFragme
|
|||||||
Fragment fragment = new LoginFragment();
|
Fragment fragment = new LoginFragment();
|
||||||
getFragmentManager().beginTransaction()
|
getFragmentManager().beginTransaction()
|
||||||
.add(R.id.fragment_container, fragment).commit();
|
.add(R.id.fragment_container, fragment).commit();
|
||||||
Log.d(TAG, "fragment added");
|
Log.d(TAG, "LoginFragment added");
|
||||||
|
}
|
||||||
|
|
||||||
|
void startGenerateFragment() {
|
||||||
|
replaceFragment(new GenerateFragment(), "gen", null);
|
||||||
|
Log.d(TAG, "GenerateFragment placed");
|
||||||
|
}
|
||||||
|
|
||||||
|
void startReviewFragment(Bundle extras) {
|
||||||
|
replaceFragment(new GenerateReviewFragment(), null, extras);
|
||||||
|
Log.d(TAG, "GenerateReviewFragment placed");
|
||||||
|
}
|
||||||
|
|
||||||
|
void replaceFragment(Fragment newFragment, String name, Bundle extras) {
|
||||||
|
if (extras != null) {
|
||||||
|
newFragment.setArguments(extras);
|
||||||
|
}
|
||||||
|
FragmentTransaction transaction = getFragmentManager().beginTransaction();
|
||||||
|
transaction.replace(R.id.fragment_container, newFragment);
|
||||||
|
transaction.addToBackStack(name);
|
||||||
|
transaction.commit();
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////
|
||||||
|
// GenerateFragment.Listener
|
||||||
|
//////////////////////////////////////////
|
||||||
|
static final String MNEMONIC_LANGUAGE = "English"; // see mnemonics/electrum-words.cpp for more
|
||||||
|
|
||||||
|
public void createWallet(final String name, final String password, final WalletCreator walletCreator) {
|
||||||
|
final GenerateFragment genFragment = (GenerateFragment)
|
||||||
|
getFragmentManager().findFragmentById(R.id.fragment_container);
|
||||||
|
File newWalletFolder = new File(getStorageRoot(), ".new");
|
||||||
|
if (!newWalletFolder.exists()) {
|
||||||
|
if (!newWalletFolder.mkdir()) {
|
||||||
|
Log.e(TAG, "Cannot create new wallet dir " + newWalletFolder.getAbsolutePath());
|
||||||
|
genFragment.walletGenerateError();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!newWalletFolder.isDirectory()) {
|
||||||
|
Log.e(TAG, "New wallet dir " + newWalletFolder.getAbsolutePath() + "is not a directory");
|
||||||
|
genFragment.walletGenerateError();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
File cacheFile = new File(newWalletFolder, name);
|
||||||
|
cacheFile.delete();
|
||||||
|
File keysFile = new File(newWalletFolder, name + ".keys");
|
||||||
|
keysFile.delete();
|
||||||
|
final File addressFile = new File(newWalletFolder, name + ".address.txt");
|
||||||
|
addressFile.delete();
|
||||||
|
|
||||||
|
if (cacheFile.exists() || keysFile.exists() || addressFile.exists()) {
|
||||||
|
Log.e(TAG, "Cannot remove all old wallet files: " + cacheFile.getAbsolutePath());
|
||||||
|
genFragment.walletGenerateError();
|
||||||
|
;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final String newWalletPath = new File(newWalletFolder, name).getAbsolutePath();
|
||||||
|
new Thread(null,
|
||||||
|
new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
Log.d(TAG, "creating wallet " + newWalletPath);
|
||||||
|
Wallet newWallet = walletCreator.createWallet(newWalletPath, password);
|
||||||
|
final String seed = newWallet.getSeed();
|
||||||
|
final String address = newWallet.getAddress();
|
||||||
|
final String view = newWallet.getSecretViewKey();
|
||||||
|
final String spend = newWallet.isWatchOnly() ? "" : "not available - use seed for recovery";
|
||||||
|
newWallet.close();
|
||||||
|
Log.d(TAG, "Created " + address);
|
||||||
|
runOnUiThread(new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
Bundle b = new Bundle();
|
||||||
|
b.putString("name", name);
|
||||||
|
b.putString("password", password);
|
||||||
|
b.putString("seed", seed);
|
||||||
|
b.putString("address", address);
|
||||||
|
b.putString("viewkey", view);
|
||||||
|
b.putString("spendkey", spend);
|
||||||
|
startReviewFragment(b);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
, "CreateWallet", MoneroHandlerThread.THREAD_STACK_SIZE).start();
|
||||||
|
}
|
||||||
|
|
||||||
|
interface WalletCreator {
|
||||||
|
Wallet createWallet(String path, String password);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onGenerate(String name, String password) {
|
||||||
|
createWallet(name, password,
|
||||||
|
new WalletCreator() {
|
||||||
|
public Wallet createWallet(String path, String password) {
|
||||||
|
return WalletManager.getInstance()
|
||||||
|
.createWallet(path, password, MNEMONIC_LANGUAGE);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onGenerate(String name, String password, final String seed, final long restoreHeight) {
|
||||||
|
createWallet(name, password,
|
||||||
|
new WalletCreator() {
|
||||||
|
public Wallet createWallet(String path, String password) {
|
||||||
|
Wallet newWallet = WalletManager.getInstance().recoveryWallet(path, seed, restoreHeight);
|
||||||
|
newWallet.setPassword(password);
|
||||||
|
newWallet.store();
|
||||||
|
return newWallet;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onGenerate(String name, String password,
|
||||||
|
final String address, final String viewKey, final String spendKey, final long restoreHeight) {
|
||||||
|
createWallet(name, password,
|
||||||
|
new WalletCreator() {
|
||||||
|
public Wallet createWallet(String path, String password) {
|
||||||
|
Wallet newWallet = WalletManager.getInstance()
|
||||||
|
.createWalletFromKeys(path, MNEMONIC_LANGUAGE, restoreHeight,
|
||||||
|
address, viewKey, spendKey);
|
||||||
|
newWallet.setPassword(password);
|
||||||
|
newWallet.store();
|
||||||
|
return newWallet;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAccept(final String name, final String password) {
|
||||||
|
final File newWalletFolder = new File(getStorageRoot(), ".new");
|
||||||
|
final File walletFolder = getStorageRoot();
|
||||||
|
new Thread(null,
|
||||||
|
new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
final String walletPath = new File(walletFolder, name).getAbsolutePath();
|
||||||
|
final boolean rc = copyWallet(walletFolder, newWalletFolder, name)
|
||||||
|
&&
|
||||||
|
(testWallet(walletPath, password) == Wallet.Status.Status_Ok);
|
||||||
|
runOnUiThread(new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
if (rc) {
|
||||||
|
getFragmentManager().popBackStack("gen",
|
||||||
|
FragmentManager.POP_BACK_STACK_INCLUSIVE);
|
||||||
|
Toast.makeText(LoginActivity.this,
|
||||||
|
getString(R.string.generate_wallet_created), Toast.LENGTH_SHORT).show();
|
||||||
|
} else {
|
||||||
|
Log.e(TAG, "Wallet store failed to " + walletPath);
|
||||||
|
Toast.makeText(LoginActivity.this,
|
||||||
|
getString(R.string.generate_wallet_create_failed_2), Toast.LENGTH_LONG).show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
, "AcceptWallet", MoneroHandlerThread.THREAD_STACK_SIZE).start();
|
||||||
|
}
|
||||||
|
|
||||||
|
Wallet.Status testWallet(String path, String password) {
|
||||||
|
Log.d(TAG, "testing wallet " + path);
|
||||||
|
Wallet aWallet = WalletManager.getInstance().openWallet(path, password);
|
||||||
|
if (aWallet == null) return Wallet.Status.Status_Error; // does this ever happen?
|
||||||
|
Wallet.Status status = aWallet.getStatus();
|
||||||
|
Log.d(TAG, "wallet tested " + aWallet.getStatus());
|
||||||
|
aWallet.close();
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean copyWallet(File dstDir, File srcDir, String name) {
|
||||||
|
boolean success = false;
|
||||||
|
try {
|
||||||
|
// TODO: the cache is corrupt if we recover (!!)
|
||||||
|
// TODO recoveryheight is ignored but not on watchonly wallet ?! - find out why
|
||||||
|
//copyFile(dstDir, srcDir, name);
|
||||||
|
copyFile(dstDir, srcDir, name + ".keys");
|
||||||
|
copyFile(dstDir, srcDir, name + ".address.txt");
|
||||||
|
success = true;
|
||||||
|
} catch (IOException ex) {
|
||||||
|
Log.e(TAG, "wallet copy failed: " + ex.getMessage());
|
||||||
|
// try to rollback
|
||||||
|
new File(dstDir, name).delete();
|
||||||
|
new File(dstDir, name + ".keys").delete();
|
||||||
|
new File(dstDir, name + ".address.txt").delete();
|
||||||
|
}
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
void copyFile(File dstDir, File srcDir, String name) throws IOException {
|
||||||
|
FileChannel inChannel = new FileInputStream(new File(srcDir, name)).getChannel();
|
||||||
|
FileChannel outChannel = new FileOutputStream(new File(dstDir, name)).getChannel();
|
||||||
|
try {
|
||||||
|
inChannel.transferTo(0, inChannel.size(), outChannel);
|
||||||
|
} finally {
|
||||||
|
if (inChannel != null)
|
||||||
|
inChannel.close();
|
||||||
|
if (outChannel != null)
|
||||||
|
outChannel.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,9 +26,7 @@ import android.view.KeyEvent;
|
|||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.view.WindowManager;
|
|
||||||
import android.view.inputmethod.EditorInfo;
|
import android.view.inputmethod.EditorInfo;
|
||||||
import android.view.inputmethod.InputMethodManager;
|
|
||||||
import android.widget.AdapterView;
|
import android.widget.AdapterView;
|
||||||
import android.widget.ArrayAdapter;
|
import android.widget.ArrayAdapter;
|
||||||
import android.widget.BaseAdapter;
|
import android.widget.BaseAdapter;
|
||||||
@ -39,44 +37,59 @@ import android.widget.Toast;
|
|||||||
import android.widget.ToggleButton;
|
import android.widget.ToggleButton;
|
||||||
|
|
||||||
import com.m2049r.xmrwallet.model.WalletManager;
|
import com.m2049r.xmrwallet.model.WalletManager;
|
||||||
|
import com.m2049r.xmrwallet.util.Helper;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Comparator;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.TreeSet;
|
||||||
|
|
||||||
public class LoginFragment extends Fragment {
|
public class LoginFragment extends Fragment {
|
||||||
private static final String TAG = "LoginFragment";
|
private static final String TAG = "LoginFragment";
|
||||||
|
public static final String WALLETNAME_PREAMBLE = "[------] ";
|
||||||
|
public static final int WALLETNAME_PREAMBLE_LENGTH = WALLETNAME_PREAMBLE.length();
|
||||||
|
|
||||||
|
|
||||||
ListView listView;
|
ListView listView;
|
||||||
List<String> walletList = new ArrayList<>();
|
Set<String> walletList = new TreeSet<>(new Comparator<String>() {
|
||||||
|
@Override
|
||||||
|
public int compare(String o1, String o2) {
|
||||||
|
return o1.substring(WALLETNAME_PREAMBLE_LENGTH).toLowerCase()
|
||||||
|
.compareTo(o2.substring(WALLETNAME_PREAMBLE_LENGTH).toLowerCase());
|
||||||
|
}
|
||||||
|
});
|
||||||
List<String> displayedList = new ArrayList<>();
|
List<String> displayedList = new ArrayList<>();
|
||||||
|
|
||||||
ToggleButton tbMainNet;
|
ToggleButton tbMainNet;
|
||||||
EditText etDaemonAddress;
|
EditText etDaemonAddress;
|
||||||
|
|
||||||
LoginFragment.LoginFragmentListener activityCallback;
|
Listener activityCallback;
|
||||||
|
|
||||||
// Container Activity must implement this interface
|
// Container Activity must implement this interface
|
||||||
public interface LoginFragmentListener {
|
public interface Listener {
|
||||||
SharedPreferences getPrefs();
|
SharedPreferences getPrefs();
|
||||||
|
|
||||||
File getStorageRoot();
|
File getStorageRoot();
|
||||||
|
|
||||||
void promptPassword(final String wallet);
|
void onWalletSelected(final String wallet);
|
||||||
|
|
||||||
|
void setTitle(String title);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onAttach(Context context) {
|
public void onAttach(Context context) {
|
||||||
super.onAttach(context);
|
super.onAttach(context);
|
||||||
if (context instanceof LoginFragment.LoginFragmentListener) {
|
if (context instanceof Listener) {
|
||||||
this.activityCallback = (LoginFragment.LoginFragmentListener) context;
|
this.activityCallback = (Listener) context;
|
||||||
} else {
|
} else {
|
||||||
throw new ClassCastException(context.toString()
|
throw new ClassCastException(context.toString()
|
||||||
+ " must implement WalletFragmentListener");
|
+ " must implement Listener");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -96,19 +109,18 @@ public class LoginFragment extends Fragment {
|
|||||||
tbMainNet = (ToggleButton) view.findViewById(R.id.tbMainNet);
|
tbMainNet = (ToggleButton) view.findViewById(R.id.tbMainNet);
|
||||||
etDaemonAddress = (EditText) view.findViewById(R.id.etDaemonAddress);
|
etDaemonAddress = (EditText) view.findViewById(R.id.etDaemonAddress);
|
||||||
|
|
||||||
getActivity().getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN);
|
Helper.hideKeyboard(getActivity());
|
||||||
|
|
||||||
etDaemonAddress.setOnClickListener(new View.OnClickListener() {
|
etDaemonAddress.setOnClickListener(new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
|
Helper.showKeyboard(getActivity());
|
||||||
imm.showSoftInput(etDaemonAddress, InputMethodManager.SHOW_IMPLICIT);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
etDaemonAddress.setOnEditorActionListener(new TextView.OnEditorActionListener() {
|
etDaemonAddress.setOnEditorActionListener(new TextView.OnEditorActionListener() {
|
||||||
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
|
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
|
||||||
if ((event != null && (event.getKeyCode() == KeyEvent.KEYCODE_ENTER)) || (actionId == EditorInfo.IME_ACTION_DONE)) {
|
if ((event != null && (event.getKeyCode() == KeyEvent.KEYCODE_ENTER)) || (actionId == EditorInfo.IME_ACTION_DONE)) {
|
||||||
getActivity().getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
|
Helper.hideKeyboard(getActivity());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@ -125,6 +137,8 @@ public class LoginFragment extends Fragment {
|
|||||||
} else {
|
} else {
|
||||||
setDaemon(daemonTestNet);
|
setDaemon(daemonTestNet);
|
||||||
}
|
}
|
||||||
|
activityCallback.setTitle(getString(R.string.app_name) + " " +
|
||||||
|
getString(mainnet ? R.string.connect_mainnet : R.string.connect_testnet));
|
||||||
filterList();
|
filterList();
|
||||||
((BaseAdapter) listView.getAdapter()).notifyDataSetChanged();
|
((BaseAdapter) listView.getAdapter()).notifyDataSetChanged();
|
||||||
}
|
}
|
||||||
@ -143,44 +157,54 @@ public class LoginFragment extends Fragment {
|
|||||||
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
||||||
EditText tvDaemonAddress = (EditText) getView().findViewById(R.id.etDaemonAddress);
|
EditText tvDaemonAddress = (EditText) getView().findViewById(R.id.etDaemonAddress);
|
||||||
if (tvDaemonAddress.getText().toString().length() == 0) {
|
if (tvDaemonAddress.getText().toString().length() == 0) {
|
||||||
Toast.makeText(getActivity(), getString(R.string.prompt_daemon_missing), Toast.LENGTH_LONG).show();
|
Toast.makeText(getActivity(), getString(R.string.prompt_daemon_missing), Toast.LENGTH_SHORT).show();
|
||||||
|
tvDaemonAddress.requestFocus();
|
||||||
|
Helper.showKeyboard(getActivity());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
String itemValue = (String) listView.getItemAtPosition(position);
|
String itemValue = (String) listView.getItemAtPosition(position);
|
||||||
if ((isMainNet() && itemValue.charAt(1) != '4')
|
|
||||||
|| (!isMainNet() && itemValue.charAt(1) != '9')) {
|
if (itemValue.length() <= (WALLETNAME_PREAMBLE_LENGTH)) {
|
||||||
|
Toast.makeText(getActivity(), getString(R.string.panic), Toast.LENGTH_LONG).show();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String x = isMainNet() ? "4-" : "9A-";
|
||||||
|
if (x.indexOf(itemValue.charAt(1)) < 0) {
|
||||||
Toast.makeText(getActivity(), getString(R.string.prompt_wrong_net), Toast.LENGTH_LONG).show();
|
Toast.makeText(getActivity(), getString(R.string.prompt_wrong_net), Toast.LENGTH_LONG).show();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final int preambleLength = "[123456] ".length();
|
|
||||||
if (itemValue.length() <= (preambleLength)) {
|
|
||||||
Toast.makeText(getActivity(), getString(R.string.panic), Toast.LENGTH_LONG).show();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!checkAndSetWalletDaemon(getDaemon(), !isMainNet())) {
|
if (!checkAndSetWalletDaemon(getDaemon(), !isMainNet())) {
|
||||||
Toast.makeText(getActivity(), getString(R.string.warn_daemon_unavailable), Toast.LENGTH_LONG).show();
|
Toast.makeText(getActivity(), getString(R.string.warn_daemon_unavailable), Toast.LENGTH_SHORT).show();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// looking good
|
// looking good
|
||||||
savePrefs(false);
|
savePrefs(false);
|
||||||
|
|
||||||
String wallet = itemValue.substring(preambleLength);
|
String wallet = itemValue.substring(WALLETNAME_PREAMBLE_LENGTH);
|
||||||
activityCallback.promptPassword(wallet);
|
if (itemValue.charAt(1) == '-') wallet = ':' + wallet;
|
||||||
|
activityCallback.onWalletSelected(wallet);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
activityCallback.setTitle(getString(R.string.app_name) + " " +
|
||||||
|
getString(isMainNet() ? R.string.connect_mainnet : R.string.connect_testnet));
|
||||||
|
|
||||||
loadList();
|
loadList();
|
||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void filterList() {
|
private void filterList() {
|
||||||
displayedList.clear();
|
displayedList.clear();
|
||||||
char x = isMainNet() ? '4' : '9';
|
String x = isMainNet() ? "4" : "9A";
|
||||||
for (String s : walletList) {
|
for (String s : walletList) {
|
||||||
if (s.charAt(1) == x) displayedList.add(s);
|
// Log.d(TAG, "filtering " + s);
|
||||||
|
if (x.indexOf(s.charAt(1)) >= 0) displayedList.add(s);
|
||||||
}
|
}
|
||||||
|
displayedList.add(WALLETNAME_PREAMBLE + getString(R.string.generate_title));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loadList() {
|
private void loadList() {
|
||||||
@ -190,7 +214,7 @@ public class LoginFragment extends Fragment {
|
|||||||
|
|
||||||
walletList.clear();
|
walletList.clear();
|
||||||
for (WalletManager.WalletInfo walletInfo : walletInfos) {
|
for (WalletManager.WalletInfo walletInfo : walletInfos) {
|
||||||
Log.d(TAG, walletInfo.address);
|
// Log.d(TAG, walletInfo.address);
|
||||||
String displayAddress = walletInfo.address;
|
String displayAddress = walletInfo.address;
|
||||||
if (displayAddress.length() == 95) {
|
if (displayAddress.length() == 95) {
|
||||||
displayAddress = walletInfo.address.substring(0, 6);
|
displayAddress = walletInfo.address.substring(0, 6);
|
||||||
@ -230,8 +254,8 @@ public class LoginFragment extends Fragment {
|
|||||||
SharedPreferences sharedPref = activityCallback.getPrefs();
|
SharedPreferences sharedPref = activityCallback.getPrefs();
|
||||||
|
|
||||||
boolean mainnet = sharedPref.getBoolean(PREF_MAINNET, false);
|
boolean mainnet = sharedPref.getBoolean(PREF_MAINNET, false);
|
||||||
daemonMainNet = sharedPref.getString(PREF_DAEMON_MAINNET, "localhost:18081");
|
daemonMainNet = sharedPref.getString(PREF_DAEMON_MAINNET, "");
|
||||||
daemonTestNet = sharedPref.getString(PREF_DAEMON_TESTNET, "localhost:28081");
|
daemonTestNet = sharedPref.getString(PREF_DAEMON_TESTNET, "");
|
||||||
|
|
||||||
setMainNet(mainnet);
|
setMainNet(mainnet);
|
||||||
if (mainnet) {
|
if (mainnet) {
|
||||||
|
@ -25,13 +25,14 @@ import android.content.ServiceConnection;
|
|||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
import android.os.PowerManager;
|
import android.os.PowerManager;
|
||||||
|
import android.support.v7.app.AppCompatActivity;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import com.m2049r.xmrwallet.model.Wallet;
|
import com.m2049r.xmrwallet.model.Wallet;
|
||||||
import com.m2049r.xmrwallet.service.WalletService;
|
import com.m2049r.xmrwallet.service.WalletService;
|
||||||
|
|
||||||
public class WalletActivity extends Activity implements WalletFragment.WalletFragmentListener,
|
public class WalletActivity extends AppCompatActivity implements WalletFragment.Listener,
|
||||||
WalletService.Observer {
|
WalletService.Observer {
|
||||||
private static final String TAG = "WalletActivity";
|
private static final String TAG = "WalletActivity";
|
||||||
|
|
||||||
@ -200,11 +201,6 @@ public class WalletActivity extends Activity implements WalletFragment.WalletFra
|
|||||||
Intent intent = new Intent(getApplicationContext(), WalletService.class);
|
Intent intent = new Intent(getApplicationContext(), WalletService.class);
|
||||||
intent.putExtra(WalletService.REQUEST, WalletService.REQUEST_CMD_STORE);
|
intent.putExtra(WalletService.REQUEST, WalletService.REQUEST_CMD_STORE);
|
||||||
startService(intent);
|
startService(intent);
|
||||||
runOnUiThread(new Runnable() {
|
|
||||||
public void run() {
|
|
||||||
Toast.makeText(getApplicationContext(), getString(R.string.status_wallet_unloading), Toast.LENGTH_LONG).show();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
Log.d(TAG, "STORE request sent");
|
Log.d(TAG, "STORE request sent");
|
||||||
} else {
|
} else {
|
||||||
Log.e(TAG, "Service not bound");
|
Log.e(TAG, "Service not bound");
|
||||||
@ -212,7 +208,7 @@ public class WalletActivity extends Activity implements WalletFragment.WalletFra
|
|||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////
|
//////////////////////////////////////////
|
||||||
// WalletFragment.WalletFragmentListener
|
// WalletFragment.Listener
|
||||||
//////////////////////////////////////////
|
//////////////////////////////////////////
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -259,6 +255,15 @@ public class WalletActivity extends Activity implements WalletFragment.WalletFra
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onWalletStored() {
|
||||||
|
runOnUiThread(new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
Toast.makeText(WalletActivity.this, getString(R.string.status_wallet_unloaded), Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onProgress(final String text) {
|
public void onProgress(final String text) {
|
||||||
//Log.d(TAG, "PROGRESS: " + text);
|
//Log.d(TAG, "PROGRESS: " + text);
|
||||||
|
@ -37,11 +37,13 @@ import com.m2049r.xmrwallet.layout.TransactionInfoAdapter;
|
|||||||
import com.m2049r.xmrwallet.model.TransactionInfo;
|
import com.m2049r.xmrwallet.model.TransactionInfo;
|
||||||
import com.m2049r.xmrwallet.model.Wallet;
|
import com.m2049r.xmrwallet.model.Wallet;
|
||||||
|
|
||||||
|
import java.text.NumberFormat;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class WalletFragment extends Fragment implements TransactionInfoAdapter.OnInteractionListener {
|
public class WalletFragment extends Fragment implements TransactionInfoAdapter.OnInteractionListener {
|
||||||
private static final String TAG = "WalletFragment";
|
private static final String TAG = "WalletFragment";
|
||||||
private TransactionInfoAdapter adapter;
|
private TransactionInfoAdapter adapter;
|
||||||
|
private NumberFormat formatter = NumberFormat.getInstance();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||||
@ -171,7 +173,7 @@ public class WalletFragment extends Fragment implements TransactionInfoAdapter.O
|
|||||||
long daemonHeight = activityCallback.getDaemonHeight();
|
long daemonHeight = activityCallback.getDaemonHeight();
|
||||||
if (!wallet.isSynchronized()) {
|
if (!wallet.isSynchronized()) {
|
||||||
long n = daemonHeight - wallet.getBlockChainHeight();
|
long n = daemonHeight - wallet.getBlockChainHeight();
|
||||||
sync = n + " " + getString(R.string.status_remaining);
|
sync = formatter.format(n) + " " + getString(R.string.status_remaining);
|
||||||
if (firstBlock == 0) {
|
if (firstBlock == 0) {
|
||||||
firstBlock = wallet.getBlockChainHeight();
|
firstBlock = wallet.getBlockChainHeight();
|
||||||
}
|
}
|
||||||
@ -180,7 +182,7 @@ public class WalletFragment extends Fragment implements TransactionInfoAdapter.O
|
|||||||
if (x == 0) x = -1;
|
if (x == 0) x = -1;
|
||||||
onProgress(x);
|
onProgress(x);
|
||||||
} else {
|
} else {
|
||||||
sync = getString(R.string.status_synced) + ": " + wallet.getBlockChainHeight();
|
sync = getString(R.string.status_synced) + ": " + formatter.format(wallet.getBlockChainHeight());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
String net = (wallet.isTestNet() ? getString(R.string.connect_testnet) : getString(R.string.connect_mainnet));
|
String net = (wallet.isTestNet() ? getString(R.string.connect_testnet) : getString(R.string.connect_mainnet));
|
||||||
@ -188,10 +190,10 @@ public class WalletFragment extends Fragment implements TransactionInfoAdapter.O
|
|||||||
connectionStatusView.setText(net + " " + daemonConnected.toString().substring(17));
|
connectionStatusView.setText(net + " " + daemonConnected.toString().substring(17));
|
||||||
}
|
}
|
||||||
|
|
||||||
WalletFragmentListener activityCallback;
|
Listener activityCallback;
|
||||||
|
|
||||||
// Container Activity must implement this interface
|
// Container Activity must implement this interface
|
||||||
public interface WalletFragmentListener {
|
public interface Listener {
|
||||||
boolean hasBoundService();
|
boolean hasBoundService();
|
||||||
|
|
||||||
Wallet.ConnectionStatus getConnectionStatus();
|
Wallet.ConnectionStatus getConnectionStatus();
|
||||||
@ -205,15 +207,11 @@ public class WalletFragment extends Fragment implements TransactionInfoAdapter.O
|
|||||||
@Override
|
@Override
|
||||||
public void onAttach(Context context) {
|
public void onAttach(Context context) {
|
||||||
super.onAttach(context);
|
super.onAttach(context);
|
||||||
if (context instanceof WalletFragmentListener) {
|
if (context instanceof Listener) {
|
||||||
this.activityCallback = (WalletFragmentListener) context;
|
this.activityCallback = (Listener) context;
|
||||||
} else {
|
} else {
|
||||||
throw new ClassCastException(context.toString()
|
throw new ClassCastException(context.toString()
|
||||||
+ " must implement WalletFragmentListener");
|
+ " must implement Listener");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void runOnUiThread(Runnable runnable) {
|
|
||||||
if (isAdded()) getActivity().runOnUiThread(runnable);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -57,7 +57,7 @@ public class WalletManager {
|
|||||||
|
|
||||||
private void manageWallet(String walletId, Wallet wallet) {
|
private void manageWallet(String walletId, Wallet wallet) {
|
||||||
if (getWallet(walletId) != null) {
|
if (getWallet(walletId) != null) {
|
||||||
throw new IllegalStateException("Wallet already under management!");
|
throw new IllegalStateException(walletId + " already under management!");
|
||||||
}
|
}
|
||||||
Log.d(TAG, "Managing " + walletId);
|
Log.d(TAG, "Managing " + walletId);
|
||||||
managedWallets.put(walletId, wallet);
|
managedWallets.put(walletId, wallet);
|
||||||
@ -65,7 +65,7 @@ public class WalletManager {
|
|||||||
|
|
||||||
private void unmanageWallet(String walletId) {
|
private void unmanageWallet(String walletId) {
|
||||||
if (getWallet(walletId) == null) {
|
if (getWallet(walletId) == null) {
|
||||||
throw new IllegalStateException("Wallet not under management!");
|
throw new IllegalStateException(walletId + " not under management!");
|
||||||
}
|
}
|
||||||
Log.d(TAG, "Unmanaging " + walletId);
|
Log.d(TAG, "Unmanaging " + walletId);
|
||||||
managedWallets.remove(walletId);
|
managedWallets.remove(walletId);
|
||||||
@ -78,6 +78,8 @@ public class WalletManager {
|
|||||||
return wallet;
|
return wallet;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private native long createWalletJ(String path, String password, String language, boolean isTestNet);
|
||||||
|
|
||||||
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);
|
||||||
@ -85,6 +87,8 @@ public class WalletManager {
|
|||||||
return wallet;
|
return wallet;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private native long openWalletJ(String path, String password, boolean isTestNet);
|
||||||
|
|
||||||
public Wallet recoveryWallet(String path, String mnemonic) {
|
public Wallet recoveryWallet(String path, String mnemonic) {
|
||||||
Wallet wallet = recoveryWallet(path, mnemonic, 0);
|
Wallet wallet = recoveryWallet(path, mnemonic, 0);
|
||||||
manageWallet(wallet.getName(), wallet);
|
manageWallet(wallet.getName(), wallet);
|
||||||
@ -98,12 +102,17 @@ public class WalletManager {
|
|||||||
return wallet;
|
return wallet;
|
||||||
}
|
}
|
||||||
|
|
||||||
private native long createWalletJ(String path, String password, String language, boolean isTestNet);
|
|
||||||
|
|
||||||
private native long openWalletJ(String path, String password, boolean isTestNet);
|
|
||||||
|
|
||||||
private native long recoveryWalletJ(String path, String mnemonic, boolean isTestNet, long restoreHeight);
|
private native long recoveryWalletJ(String path, String mnemonic, boolean isTestNet, long restoreHeight);
|
||||||
|
|
||||||
|
public Wallet createWalletFromKeys(String path, String language, long restoreHeight,
|
||||||
|
String addressString, String viewKeyString, String spendKeyString) {
|
||||||
|
long walletHandle = createWalletFromKeysJ(path, language, isTestNet(), restoreHeight,
|
||||||
|
addressString, viewKeyString, spendKeyString);
|
||||||
|
Wallet wallet = new Wallet(walletHandle);
|
||||||
|
manageWallet(wallet.getName(), wallet);
|
||||||
|
return wallet;
|
||||||
|
}
|
||||||
|
|
||||||
private native long createWalletFromKeysJ(String path, String language,
|
private native long createWalletFromKeysJ(String path, String language,
|
||||||
boolean isTestNet,
|
boolean isTestNet,
|
||||||
long restoreHeight,
|
long restoreHeight,
|
||||||
|
@ -111,7 +111,8 @@ public class WalletService extends Service {
|
|||||||
fullRefresh = true;
|
fullRefresh = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
observer.onRefreshed(wallet, fullRefresh);
|
if (observer != null)
|
||||||
|
observer.onRefreshed(wallet, fullRefresh);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -191,6 +192,8 @@ public class WalletService extends Service {
|
|||||||
void onProgress(String text);
|
void onProgress(String text);
|
||||||
|
|
||||||
void onProgress(int n);
|
void onProgress(int n);
|
||||||
|
|
||||||
|
void onWalletStored();
|
||||||
}
|
}
|
||||||
|
|
||||||
String progressText = null;
|
String progressText = null;
|
||||||
@ -257,6 +260,7 @@ public class WalletService extends Service {
|
|||||||
Log.d(TAG, "storing wallet: " + myWallet.getName());
|
Log.d(TAG, "storing wallet: " + myWallet.getName());
|
||||||
getWallet().store();
|
getWallet().store();
|
||||||
Log.d(TAG, "wallet stored: " + myWallet.getName());
|
Log.d(TAG, "wallet stored: " + myWallet.getName());
|
||||||
|
if (observer != null) observer.onWalletStored();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -351,6 +355,7 @@ public class WalletService extends Service {
|
|||||||
if (listener == null) {
|
if (listener == null) {
|
||||||
Log.d(TAG, "start() loadWallet");
|
Log.d(TAG, "start() loadWallet");
|
||||||
Wallet aWallet = loadWallet(walletName, walletPassword);
|
Wallet aWallet = loadWallet(walletName, walletPassword);
|
||||||
|
// TODO check aWallet and die gracefully if neccessary
|
||||||
listener = new MyWalletListener(aWallet);
|
listener = new MyWalletListener(aWallet);
|
||||||
listener.start();
|
listener.start();
|
||||||
showProgress(100);
|
showProgress(100);
|
||||||
@ -416,6 +421,8 @@ public class WalletService extends Service {
|
|||||||
WalletManager.getInstance().close(wallet); // TODO close() failed?
|
WalletManager.getInstance().close(wallet); // TODO close() failed?
|
||||||
wallet = null;
|
wallet = null;
|
||||||
// TODO what do we do with the progress??
|
// TODO what do we do with the progress??
|
||||||
|
// TODO tell the activity this failed
|
||||||
|
// this crashes in MyWalletListener(Wallet aWallet) as wallet == null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return wallet;
|
return wallet;
|
||||||
|
@ -18,10 +18,13 @@ package com.m2049r.xmrwallet.util;
|
|||||||
|
|
||||||
import android.Manifest;
|
import android.Manifest;
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
|
import android.app.Dialog;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.os.Environment;
|
import android.os.Environment;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
import android.view.WindowManager;
|
||||||
|
import android.view.inputmethod.InputMethodManager;
|
||||||
|
|
||||||
import com.m2049r.xmrwallet.R;
|
import com.m2049r.xmrwallet.R;
|
||||||
|
|
||||||
@ -82,4 +85,26 @@ public class Helper {
|
|||||||
return Environment.MEDIA_MOUNTED.equals(state);
|
return Environment.MEDIA_MOUNTED.equals(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static public void showKeyboard(Activity act) {
|
||||||
|
InputMethodManager imm = (InputMethodManager) act.getSystemService(Context.INPUT_METHOD_SERVICE);
|
||||||
|
imm.showSoftInput(act.getCurrentFocus(), InputMethodManager.SHOW_IMPLICIT);
|
||||||
|
}
|
||||||
|
|
||||||
|
static public void hideKeyboard(Activity act) {
|
||||||
|
if (act.getCurrentFocus() == null) {
|
||||||
|
act.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN);
|
||||||
|
} else {
|
||||||
|
InputMethodManager imm = (InputMethodManager) act.getSystemService(Context.INPUT_METHOD_SERVICE);
|
||||||
|
imm.hideSoftInputFromWindow((null == act.getCurrentFocus()) ? null : act.getCurrentFocus().getWindowToken(),
|
||||||
|
InputMethodManager.HIDE_NOT_ALWAYS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static public void showKeyboard(Dialog dialog) {
|
||||||
|
dialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static public void hideKeyboardAlways(Activity act) {
|
||||||
|
act.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
107
app/src/main/res/layout/gen_fragment.xml
Normal file
107
app/src/main/res/layout/gen_fragment.xml
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:weightSum="2">
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/etWalletName"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:hint="@string/generate_name_hint"
|
||||||
|
android:imeOptions="actionNext"
|
||||||
|
android:inputType="text"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:textAlignment="center"
|
||||||
|
android:textSize="16sp" />
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/etWalletPassword"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:hint="@string/generate_password_hint"
|
||||||
|
android:imeOptions="actionNext"
|
||||||
|
android:inputType="text"
|
||||||
|
android:textAlignment="center"
|
||||||
|
android:textSize="16sp" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/etWalletMnemonic"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:hint="@string/generate_mnemonic_hint"
|
||||||
|
android:imeOptions="actionNext"
|
||||||
|
android:inputType="text"
|
||||||
|
android:textAlignment="center"
|
||||||
|
android:textSize="16sp" />
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/etWalletAddress"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:hint="@string/generate_address_hint"
|
||||||
|
android:imeOptions="actionNext"
|
||||||
|
android:inputType="text"
|
||||||
|
android:textAlignment="center"
|
||||||
|
android:textSize="16sp" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/llRestoreKeys"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="center"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:visibility="invisible">
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/etWalletViewKey"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:hint="@string/generate_viewkey_hint"
|
||||||
|
android:imeOptions="actionNext"
|
||||||
|
android:inputType="text"
|
||||||
|
android:textAlignment="center"
|
||||||
|
android:textSize="16sp" />
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/etWalletSpendKey"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:hint="@string/generate_spendkey_hint"
|
||||||
|
android:imeOptions="actionNext"
|
||||||
|
android:inputType="text"
|
||||||
|
android:textAlignment="center"
|
||||||
|
android:textSize="16sp" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/etWalletRestoreHeight"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:hint="@string/generate_restoreheight_hint"
|
||||||
|
android:imeOptions="actionNext"
|
||||||
|
android:inputType="number"
|
||||||
|
android:textAlignment="center"
|
||||||
|
android:textSize="16sp"
|
||||||
|
android:visibility="invisible" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/bGenerate"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="8dp"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:background="@color/colorPrimary"
|
||||||
|
android:enabled="false"
|
||||||
|
android:text="@string/generate_buttonGenerate" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
151
app/src/main/res/layout/gen_review_fragment.xml
Normal file
151
app/src/main/res/layout/gen_review_fragment.xml
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:weightSum="2">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvWalletLabel"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:text="@string/generate_wallet_label"
|
||||||
|
android:textAlignment="center"
|
||||||
|
android:textColor="@color/colorAccent"
|
||||||
|
android:textSize="16sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvWalletPasswordLabel"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:text="@string/generate_password_label"
|
||||||
|
android:textAlignment="center"
|
||||||
|
android:textColor="@color/colorAccent"
|
||||||
|
android:textSize="16sp" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:layout_marginBottom="8dp"
|
||||||
|
android:weightSum="2">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvWalletName"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:text="@string/generate_name_hint"
|
||||||
|
android:textAlignment="center"
|
||||||
|
android:textColor="@color/colorPrimaryDark"
|
||||||
|
android:textSize="16sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvWalletPassword"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:text="@string/generate_password_hint"
|
||||||
|
android:textAlignment="center"
|
||||||
|
android:textColor="@color/colorPrimaryDark"
|
||||||
|
android:textSize="16sp" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvWalletMnemonicLabel"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/generate_mnemonic_label"
|
||||||
|
android:textAlignment="center"
|
||||||
|
android:textColor="@color/colorAccent"
|
||||||
|
android:textSize="16sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvWalletMnemonic"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/generate_mnemonic_placeholder"
|
||||||
|
android:textAlignment="center"
|
||||||
|
android:textColor="@color/colorPrimaryDark"
|
||||||
|
android:textSize="16sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvWalletAddressLabel"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:text="@string/generate_address_label"
|
||||||
|
android:textAlignment="center"
|
||||||
|
android:textColor="@color/colorAccent"
|
||||||
|
android:textSize="16sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvWalletAddress"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:selectAllOnFocus="true"
|
||||||
|
android:text="@string/generate_address_placeholder"
|
||||||
|
android:textAlignment="center"
|
||||||
|
android:textColor="@color/colorPrimaryDark"
|
||||||
|
android:textIsSelectable="true"
|
||||||
|
android:textSize="16sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvWalletViewKeyLabel"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:text="@string/generate_viewkey_label"
|
||||||
|
android:textAlignment="center"
|
||||||
|
android:textColor="@color/colorAccent"
|
||||||
|
android:textSize="16sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvWalletViewKey"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:selectAllOnFocus="true"
|
||||||
|
android:text="@string/generate_viewkey_placeholder"
|
||||||
|
android:textAlignment="center"
|
||||||
|
android:textColor="@color/colorPrimaryDark"
|
||||||
|
android:textIsSelectable="true"
|
||||||
|
android:textSize="16sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvWalletSpendKeyLabel"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:text="@string/generate_spendkey_label"
|
||||||
|
android:textAlignment="center"
|
||||||
|
android:textColor="@color/colorAccent"
|
||||||
|
android:textSize="16sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvWalletSpendKey"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:selectAllOnFocus="true"
|
||||||
|
android:text="@string/generate_spendkey_placeholder"
|
||||||
|
android:textAlignment="center"
|
||||||
|
android:textColor="@color/colorPrimaryDark"
|
||||||
|
android:textIsSelectable="true"
|
||||||
|
android:textSize="16sp" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/bAccept"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:background="@color/colorPrimary"
|
||||||
|
android:text="@string/generate_button_accept" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
@ -1,4 +1,17 @@
|
|||||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
android:id="@+id/fragment_container"
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent" />
|
android:layout_height="match_parent"
|
||||||
|
android:gravity="center_horizontal"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:paddingBottom="@dimen/activity_vertical_margin"
|
||||||
|
android:paddingLeft="@dimen/activity_horizontal_margin"
|
||||||
|
android:paddingRight="@dimen/activity_horizontal_margin"
|
||||||
|
android:paddingTop="@dimen/activity_vertical_margin">
|
||||||
|
|
||||||
|
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:id="@+id/fragment_container"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
@ -1,18 +1,11 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:gravity="center_horizontal"
|
android:orientation="vertical">
|
||||||
android:orientation="vertical"
|
|
||||||
android:paddingBottom="@dimen/activity_vertical_margin"
|
|
||||||
android:paddingLeft="@dimen/activity_horizontal_margin"
|
|
||||||
android:paddingRight="@dimen/activity_horizontal_margin"
|
|
||||||
android:paddingTop="@dimen/activity_vertical_margin"
|
|
||||||
tools:context="com.m2049r.xmrwallet.LoginActivity">
|
|
||||||
|
|
||||||
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content">
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
@ -1,4 +1,17 @@
|
|||||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
android:id="@+id/fragment_container"
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent" />
|
android:layout_height="match_parent"
|
||||||
|
android:gravity="center_horizontal"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:paddingBottom="@dimen/activity_vertical_margin"
|
||||||
|
android:paddingLeft="@dimen/activity_horizontal_margin"
|
||||||
|
android:paddingRight="@dimen/activity_horizontal_margin"
|
||||||
|
android:paddingTop="@dimen/activity_vertical_margin">
|
||||||
|
|
||||||
|
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:id="@+id/fragment_container"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
@ -1,16 +1,10 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:background="@android:color/white"
|
android:orientation="vertical">
|
||||||
android:orientation="vertical"
|
|
||||||
android:paddingBottom="@dimen/activity_vertical_margin"
|
|
||||||
android:paddingLeft="@dimen/activity_horizontal_margin"
|
|
||||||
android:paddingRight="@dimen/activity_horizontal_margin"
|
|
||||||
android:paddingTop="@dimen/activity_vertical_margin"
|
|
||||||
>
|
|
||||||
|
|
||||||
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
@ -11,14 +11,16 @@
|
|||||||
<string name="status_walletlist_loading">Loading Wallet List</string>
|
<string name="status_walletlist_loading">Loading Wallet List</string>
|
||||||
<string name="status_wallet_loading">Loading Wallet …</string>
|
<string name="status_wallet_loading">Loading Wallet …</string>
|
||||||
<string name="status_wallet_unloading">Saving Wallet</string>
|
<string name="status_wallet_unloading">Saving Wallet</string>
|
||||||
|
<string name="status_wallet_unloaded">Wallet saved</string>
|
||||||
<string name="status_wallet_connecting">Connecting …</string>
|
<string name="status_wallet_connecting">Connecting …</string>
|
||||||
<string name="status_working">Working on it …</string>
|
<string name="status_working">Working on it …</string>
|
||||||
|
|
||||||
<string name="prompt_password">Password for</string>
|
<string name="prompt_password">Password for</string>
|
||||||
<string name="bad_password">Bad password!</string>
|
<string name="bad_password">Bad password!</string>
|
||||||
|
<string name="bad_wallet">Wallet does not exists!</string>
|
||||||
<string name="prompt_daemon_missing">Daemon address must be set!</string>
|
<string name="prompt_daemon_missing">Daemon address must be set!</string>
|
||||||
<string name="prompt_wrong_net">Daemon type does not fit to wallet!</string>
|
<string name="prompt_wrong_net">Wallet does not match selected net</string>
|
||||||
<string name="warn_daemon_unavailable">Cannot connect to daemon!</string>
|
<string name="warn_daemon_unavailable">Cannot connect to daemon! Try again.</string>
|
||||||
<string name="panic">Something\'s wrong!</string>
|
<string name="panic">Something\'s wrong!</string>
|
||||||
|
|
||||||
<string name="title_amount">Amount</string>
|
<string name="title_amount">Amount</string>
|
||||||
@ -43,4 +45,44 @@
|
|||||||
<string name="message_strorage_not_writable">External Storage is not writable! Panic!</string>
|
<string name="message_strorage_not_writable">External Storage is not writable! Panic!</string>
|
||||||
<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="generate_title">Generate Wallet</string>
|
||||||
|
<string name="generate_name_hint">Wallet Name</string>
|
||||||
|
<string name="generate_password_hint">Wallet Password</string>
|
||||||
|
<string name="generate_buttonGenerate">Do it already!</string>
|
||||||
|
<string name="generate_seed">Mnemonic Seed</string>
|
||||||
|
<string name="generate_button_accept">I have noted the mnemonic seed\nNow, I want to loose all my money!</string>
|
||||||
|
<string name="generate_button_reset">I\'m confused - Let me start again!</string>
|
||||||
|
|
||||||
|
<string name="generate_wallet_watchonly"><Watch Only Wallet></string>
|
||||||
|
|
||||||
|
<string name="generate_wallet_exists">Wallet exists! Choose another name</string>
|
||||||
|
<string name="generate_wallet_created">Wallet created</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_viewkey_placeholder">e2b99f4cc3d644774c4b118db05f8aa9967583a01ca4d47058c3860af10bd306</string>
|
||||||
|
<string name="generate_spendkey_placeholder">300a54208ab0a638a8407a12e3de946da76f5a9ded303338452332ec7755210d</string>
|
||||||
|
<string name="generate_mnemonic_placeholder">camp feline inflamed memoir afloat eight alerts females gutter cogs menu waveform gather tawny judge gusts yahoo doctor females biscuit alchemy reef agony austere camp</string>
|
||||||
|
<string name="generate_restoreheight_placeholder">1307882</string>
|
||||||
|
|
||||||
|
<string name="generate_address_hint">Public Address (optional)</string>
|
||||||
|
<string name="generate_viewkey_hint">View Key</string>
|
||||||
|
<string name="generate_spendkey_hint">Spend Key (optional)</string>
|
||||||
|
<string name="generate_mnemonic_hint">Mnemonic Seed (optional)</string>
|
||||||
|
<string name="generate_restoreheight_hint">Restore Height (optional)</string>
|
||||||
|
|
||||||
|
<string name="generate_wallet_label">Wallet</string>
|
||||||
|
<string name="generate_password_label">Password</string>
|
||||||
|
<string name="generate_address_label">Public Address</string>
|
||||||
|
<string name="generate_viewkey_label">View Key</string>
|
||||||
|
<string name="generate_spendkey_label">Spend Key</string>
|
||||||
|
<string name="generate_mnemonic_label">Mnemonic Seed</string>
|
||||||
|
<string name="generate_restoreheight_label">Restore Height:</string>
|
||||||
|
|
||||||
|
<string name="generate_check_keys">Check your keys!</string>
|
||||||
|
<string name="generate_check_key">Check your key!</string>
|
||||||
|
<string name="generate_check_address">Check your address!</string>
|
||||||
|
<string name="generate_check_mnemonic">Check your mnemonic seed!</string>
|
||||||
|
<string name="generate_check_something">Check your entry!</string>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user