diff --git a/app/.gitignore b/app/.gitignore
index e7838274..b19c2073 100644
--- a/app/.gitignore
+++ b/app/.gitignore
@@ -1,2 +1,3 @@
 .externalNativeBuild
 build
+app.iml
diff --git a/app/app.iml b/app/app.iml
deleted file mode 100644
index a6fa2860..00000000
--- a/app/app.iml
+++ /dev/null
@@ -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>
\ No newline at end of file
diff --git a/app/src/main/cpp/monerujo.cpp b/app/src/main/cpp/monerujo.cpp
index 3c11364c..1d14de8a 100644
--- a/app/src/main/cpp/monerujo.cpp
+++ b/app/src/main/cpp/monerujo.cpp
@@ -302,7 +302,7 @@ Java_com_m2049r_xmrwallet_model_WalletManager_recoveryWalletJ(JNIEnv *env, jobje
     return reinterpret_cast<jlong>(wallet);
 }
 
-JNIEXPORT jboolean JNICALL
+JNIEXPORT jlong JNICALL
 Java_com_m2049r_xmrwallet_model_WalletManager_createWalletFromKeysJ(JNIEnv *env, jobject instance,
                                                                     jstring path, jstring language,
                                                                     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);
 
-// actually a WalletManager function, but logically in Wallet
+// actually a WalletManager function, but logically in onWalletSelected
 JNIEXPORT jboolean JNICALL
 Java_com_m2049r_xmrwallet_model_WalletManager_closeJ(JNIEnv *env, jobject instance,
                                                      jobject walletInstance) {
diff --git a/app/src/main/java/com/m2049r/xmrwallet/GenerateFragment.java b/app/src/main/java/com/m2049r/xmrwallet/GenerateFragment.java
new file mode 100644
index 00000000..d1f846ad
--- /dev/null
+++ b/app/src/main/java/com/m2049r/xmrwallet/GenerateFragment.java
@@ -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");
+        }
+    }
+
+}
diff --git a/app/src/main/java/com/m2049r/xmrwallet/GenerateReviewFragment.java b/app/src/main/java/com/m2049r/xmrwallet/GenerateReviewFragment.java
new file mode 100644
index 00000000..8089323d
--- /dev/null
+++ b/app/src/main/java/com/m2049r/xmrwallet/GenerateReviewFragment.java
@@ -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");
+        }
+    }
+}
diff --git a/app/src/main/java/com/m2049r/xmrwallet/LoginActivity.java b/app/src/main/java/com/m2049r/xmrwallet/LoginActivity.java
index 9079c038..1ddc8df8 100644
--- a/app/src/main/java/com/m2049r/xmrwallet/LoginActivity.java
+++ b/app/src/main/java/com/m2049r/xmrwallet/LoginActivity.java
@@ -19,29 +19,39 @@ package com.m2049r.xmrwallet;
 import android.app.Activity;
 import android.app.AlertDialog;
 import android.app.Fragment;
+import android.app.FragmentManager;
+import android.app.FragmentTransaction;
 import android.content.Context;
 import android.content.DialogInterface;
 import android.content.Intent;
 import android.content.SharedPreferences;
 import android.content.pm.PackageManager;
 import android.os.Bundle;
+import android.provider.MediaStore;
 import android.support.annotation.NonNull;
+import android.support.v7.app.AppCompatActivity;
 import android.util.Log;
 import android.view.KeyEvent;
 import android.view.LayoutInflater;
 import android.view.View;
-import android.view.WindowManager;
 import android.view.inputmethod.EditorInfo;
 import android.widget.EditText;
 import android.widget.TextView;
 import android.widget.Toast;
 
+import com.m2049r.xmrwallet.model.Wallet;
 import com.m2049r.xmrwallet.model.WalletManager;
+import com.m2049r.xmrwallet.service.MoneroHandlerThread;
 import com.m2049r.xmrwallet.util.Helper;
 
 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 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
-    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;
         LayoutInflater li = LayoutInflater.from(context);
         View promptsView = li.inflate(R.layout.prompt_password, null);
@@ -81,37 +108,40 @@ public class LoginActivity extends Activity implements LoginFragment.LoginFragme
                 .setPositiveButton("OK",
                         new DialogInterface.OnClickListener() {
                             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();
                                 processPasswordEntry(wallet, pass);
+                                passwordDialog = null;
                             }
                         })
                 .setNegativeButton("Cancel",
                         new DialogInterface.OnClickListener() {
                             public void onClick(DialogInterface dialog, int id) {
-                                getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
+                                Helper.hideKeyboardAlways(LoginActivity.this);
                                 dialog.cancel();
+                                passwordDialog = null;
                             }
                         });
 
-        final AlertDialog alertDialog = alertDialogBuilder.create();
-        // request keyboard
-        alertDialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
+        passwordDialog = alertDialogBuilder.create();
+        Helper.showKeyboard(passwordDialog);
+
         // accept keyboard "ok"
         etPassword.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_DONE)) {
-                    getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
+                    Helper.hideKeyboardAlways(LoginActivity.this);
                     String pass = etPassword.getText().toString();
-                    alertDialog.cancel();
+                    passwordDialog.cancel();
                     processPasswordEntry(wallet, pass);
+                    passwordDialog = null;
                     return false;
                 }
                 return false;
             }
         });
 
-        alertDialog.show();
+        passwordDialog.show();
     }
 
     private boolean checkWalletPassword(String walletName, String password) {
@@ -130,7 +160,7 @@ public class LoginActivity extends Activity implements LoginFragment.LoginFragme
     }
 
     ////////////////////////////////////////
-    // LoginFragment.LoginFragmentListener
+    // LoginFragment.Listener
     ////////////////////////////////////////
     @Override
     public SharedPreferences getPrefs() {
@@ -142,6 +172,11 @@ public class LoginActivity extends Activity implements LoginFragment.LoginFragme
         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 {
                     String msg = getString(R.string.message_strorage_not_permitted);
                     Log.e(TAG, msg);
-                    Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
+                    Toast.makeText(this, msg, Toast.LENGTH_LONG).show();
                     //throw new IllegalStateException(msg);
                 }
                 break;
@@ -190,6 +225,209 @@ public class LoginActivity extends Activity implements LoginFragment.LoginFragme
         Fragment fragment = new LoginFragment();
         getFragmentManager().beginTransaction()
                 .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();
+        }
     }
 }
diff --git a/app/src/main/java/com/m2049r/xmrwallet/LoginFragment.java b/app/src/main/java/com/m2049r/xmrwallet/LoginFragment.java
index f925d08a..50e06272 100644
--- a/app/src/main/java/com/m2049r/xmrwallet/LoginFragment.java
+++ b/app/src/main/java/com/m2049r/xmrwallet/LoginFragment.java
@@ -26,9 +26,7 @@ import android.view.KeyEvent;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
-import android.view.WindowManager;
 import android.view.inputmethod.EditorInfo;
-import android.view.inputmethod.InputMethodManager;
 import android.widget.AdapterView;
 import android.widget.ArrayAdapter;
 import android.widget.BaseAdapter;
@@ -39,44 +37,59 @@ import android.widget.Toast;
 import android.widget.ToggleButton;
 
 import com.m2049r.xmrwallet.model.WalletManager;
+import com.m2049r.xmrwallet.util.Helper;
 
 import java.io.File;
 import java.io.IOException;
 import java.net.InetSocketAddress;
 import java.net.Socket;
 import java.util.ArrayList;
+import java.util.Comparator;
 import java.util.Date;
 import java.util.List;
+import java.util.Set;
+import java.util.TreeSet;
 
 public class LoginFragment extends Fragment {
     private static final String TAG = "LoginFragment";
+    public static final String WALLETNAME_PREAMBLE = "[------] ";
+    public static final int WALLETNAME_PREAMBLE_LENGTH = WALLETNAME_PREAMBLE.length();
+
 
     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<>();
 
     ToggleButton tbMainNet;
     EditText etDaemonAddress;
 
-    LoginFragment.LoginFragmentListener activityCallback;
+    Listener activityCallback;
 
     // Container Activity must implement this interface
-    public interface LoginFragmentListener {
+    public interface Listener {
         SharedPreferences getPrefs();
 
         File getStorageRoot();
 
-        void promptPassword(final String wallet);
+        void onWalletSelected(final String wallet);
+
+        void setTitle(String title);
     }
 
     @Override
     public void onAttach(Context context) {
         super.onAttach(context);
-        if (context instanceof LoginFragment.LoginFragmentListener) {
-            this.activityCallback = (LoginFragment.LoginFragmentListener) context;
+        if (context instanceof Listener) {
+            this.activityCallback = (Listener) context;
         } else {
             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);
         etDaemonAddress = (EditText) view.findViewById(R.id.etDaemonAddress);
 
-        getActivity().getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN);
+        Helper.hideKeyboard(getActivity());
 
         etDaemonAddress.setOnClickListener(new View.OnClickListener() {
             @Override
             public void onClick(View v) {
-                InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
-                imm.showSoftInput(etDaemonAddress, InputMethodManager.SHOW_IMPLICIT);
+                Helper.showKeyboard(getActivity());
             }
         });
         etDaemonAddress.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_DONE)) {
-                    getActivity().getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
+                    Helper.hideKeyboard(getActivity());
                     return false;
                 }
                 return false;
@@ -125,6 +137,8 @@ public class LoginFragment extends Fragment {
                 } else {
                     setDaemon(daemonTestNet);
                 }
+                activityCallback.setTitle(getString(R.string.app_name) + " " +
+                        getString(mainnet ? R.string.connect_mainnet : R.string.connect_testnet));
                 filterList();
                 ((BaseAdapter) listView.getAdapter()).notifyDataSetChanged();
             }
@@ -143,44 +157,54 @@ public class LoginFragment extends Fragment {
             public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                 EditText tvDaemonAddress = (EditText) getView().findViewById(R.id.etDaemonAddress);
                 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;
                 }
 
                 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();
                     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())) {
-                    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;
                 }
 
                 // looking good
                 savePrefs(false);
 
-                String wallet = itemValue.substring(preambleLength);
-                activityCallback.promptPassword(wallet);
+                String wallet = itemValue.substring(WALLETNAME_PREAMBLE_LENGTH);
+                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();
         return view;
     }
 
     private void filterList() {
         displayedList.clear();
-        char x = isMainNet() ? '4' : '9';
+        String x = isMainNet() ? "4" : "9A";
         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() {
@@ -190,7 +214,7 @@ public class LoginFragment extends Fragment {
 
         walletList.clear();
         for (WalletManager.WalletInfo walletInfo : walletInfos) {
-            Log.d(TAG, walletInfo.address);
+            // Log.d(TAG, walletInfo.address);
             String displayAddress = walletInfo.address;
             if (displayAddress.length() == 95) {
                 displayAddress = walletInfo.address.substring(0, 6);
@@ -230,8 +254,8 @@ public class LoginFragment extends Fragment {
         SharedPreferences sharedPref = activityCallback.getPrefs();
 
         boolean mainnet = sharedPref.getBoolean(PREF_MAINNET, false);
-        daemonMainNet = sharedPref.getString(PREF_DAEMON_MAINNET, "localhost:18081");
-        daemonTestNet = sharedPref.getString(PREF_DAEMON_TESTNET, "localhost:28081");
+        daemonMainNet = sharedPref.getString(PREF_DAEMON_MAINNET, "");
+        daemonTestNet = sharedPref.getString(PREF_DAEMON_TESTNET, "");
 
         setMainNet(mainnet);
         if (mainnet) {
diff --git a/app/src/main/java/com/m2049r/xmrwallet/WalletActivity.java b/app/src/main/java/com/m2049r/xmrwallet/WalletActivity.java
index 40ef7122..a0c5620b 100644
--- a/app/src/main/java/com/m2049r/xmrwallet/WalletActivity.java
+++ b/app/src/main/java/com/m2049r/xmrwallet/WalletActivity.java
@@ -25,13 +25,14 @@ import android.content.ServiceConnection;
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.PowerManager;
+import android.support.v7.app.AppCompatActivity;
 import android.util.Log;
 import android.widget.Toast;
 
 import com.m2049r.xmrwallet.model.Wallet;
 import com.m2049r.xmrwallet.service.WalletService;
 
-public class WalletActivity extends Activity implements WalletFragment.WalletFragmentListener,
+public class WalletActivity extends AppCompatActivity implements WalletFragment.Listener,
         WalletService.Observer {
     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.putExtra(WalletService.REQUEST, WalletService.REQUEST_CMD_STORE);
             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");
         } else {
             Log.e(TAG, "Service not bound");
@@ -212,7 +208,7 @@ public class WalletActivity extends Activity implements WalletFragment.WalletFra
     }
 
     //////////////////////////////////////////
-    // WalletFragment.WalletFragmentListener
+    // WalletFragment.Listener
     //////////////////////////////////////////
 
     @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
     public void onProgress(final String text) {
         //Log.d(TAG, "PROGRESS: " + text);
diff --git a/app/src/main/java/com/m2049r/xmrwallet/WalletFragment.java b/app/src/main/java/com/m2049r/xmrwallet/WalletFragment.java
index 50791bdd..c708b3c8 100644
--- a/app/src/main/java/com/m2049r/xmrwallet/WalletFragment.java
+++ b/app/src/main/java/com/m2049r/xmrwallet/WalletFragment.java
@@ -37,11 +37,13 @@ import com.m2049r.xmrwallet.layout.TransactionInfoAdapter;
 import com.m2049r.xmrwallet.model.TransactionInfo;
 import com.m2049r.xmrwallet.model.Wallet;
 
+import java.text.NumberFormat;
 import java.util.List;
 
 public class WalletFragment extends Fragment implements TransactionInfoAdapter.OnInteractionListener {
     private static final String TAG = "WalletFragment";
     private TransactionInfoAdapter adapter;
+    private NumberFormat formatter = NumberFormat.getInstance();
 
     @Override
     public View onCreateView(LayoutInflater inflater, ViewGroup container,
@@ -171,7 +173,7 @@ public class WalletFragment extends Fragment implements TransactionInfoAdapter.O
             long daemonHeight = activityCallback.getDaemonHeight();
             if (!wallet.isSynchronized()) {
                 long n = daemonHeight - wallet.getBlockChainHeight();
-                sync = n + " " + getString(R.string.status_remaining);
+                sync = formatter.format(n) + " " + getString(R.string.status_remaining);
                 if (firstBlock == 0) {
                     firstBlock = wallet.getBlockChainHeight();
                 }
@@ -180,7 +182,7 @@ public class WalletFragment extends Fragment implements TransactionInfoAdapter.O
                 if (x == 0) x = -1;
                 onProgress(x);
             } 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));
@@ -188,10 +190,10 @@ public class WalletFragment extends Fragment implements TransactionInfoAdapter.O
         connectionStatusView.setText(net + " " + daemonConnected.toString().substring(17));
     }
 
-    WalletFragmentListener activityCallback;
+    Listener activityCallback;
 
     // Container Activity must implement this interface
-    public interface WalletFragmentListener {
+    public interface Listener {
         boolean hasBoundService();
 
         Wallet.ConnectionStatus getConnectionStatus();
@@ -205,15 +207,11 @@ public class WalletFragment extends Fragment implements TransactionInfoAdapter.O
     @Override
     public void onAttach(Context context) {
         super.onAttach(context);
-        if (context instanceof WalletFragmentListener) {
-            this.activityCallback = (WalletFragmentListener) context;
+        if (context instanceof Listener) {
+            this.activityCallback = (Listener) context;
         } else {
             throw new ClassCastException(context.toString()
-                    + " must implement WalletFragmentListener");
+                    + " must implement Listener");
         }
     }
-
-    private void runOnUiThread(Runnable runnable) {
-        if (isAdded()) getActivity().runOnUiThread(runnable);
-    }
 }
diff --git a/app/src/main/java/com/m2049r/xmrwallet/model/WalletManager.java b/app/src/main/java/com/m2049r/xmrwallet/model/WalletManager.java
index 2757877f..357027bb 100644
--- a/app/src/main/java/com/m2049r/xmrwallet/model/WalletManager.java
+++ b/app/src/main/java/com/m2049r/xmrwallet/model/WalletManager.java
@@ -57,7 +57,7 @@ public class WalletManager {
 
     private void manageWallet(String walletId, Wallet wallet) {
         if (getWallet(walletId) != null) {
-            throw new IllegalStateException("Wallet already under management!");
+            throw new IllegalStateException(walletId + " already under management!");
         }
         Log.d(TAG, "Managing " + walletId);
         managedWallets.put(walletId, wallet);
@@ -65,7 +65,7 @@ public class WalletManager {
 
     private void unmanageWallet(String walletId) {
         if (getWallet(walletId) == null) {
-            throw new IllegalStateException("Wallet not under management!");
+            throw new IllegalStateException(walletId + " not under management!");
         }
         Log.d(TAG, "Unmanaging " + walletId);
         managedWallets.remove(walletId);
@@ -78,6 +78,8 @@ public class WalletManager {
         return wallet;
     }
 
+    private native long createWalletJ(String path, String password, String language, boolean isTestNet);
+
     public Wallet openWallet(String path, String password) {
         long walletHandle = openWalletJ(path, password, isTestNet());
         Wallet wallet = new Wallet(walletHandle);
@@ -85,6 +87,8 @@ public class WalletManager {
         return wallet;
     }
 
+    private native long openWalletJ(String path, String password, boolean isTestNet);
+
     public Wallet recoveryWallet(String path, String mnemonic) {
         Wallet wallet = recoveryWallet(path, mnemonic, 0);
         manageWallet(wallet.getName(), wallet);
@@ -98,12 +102,17 @@ public class WalletManager {
         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);
 
+    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,
                                               boolean isTestNet,
                                               long restoreHeight,
diff --git a/app/src/main/java/com/m2049r/xmrwallet/service/WalletService.java b/app/src/main/java/com/m2049r/xmrwallet/service/WalletService.java
index 436d08f0..ce4bc3c9 100644
--- a/app/src/main/java/com/m2049r/xmrwallet/service/WalletService.java
+++ b/app/src/main/java/com/m2049r/xmrwallet/service/WalletService.java
@@ -111,7 +111,8 @@ public class WalletService extends Service {
                             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(int n);
+
+        void onWalletStored();
     }
 
     String progressText = null;
@@ -257,6 +260,7 @@ public class WalletService extends Service {
                         Log.d(TAG, "storing wallet: " + myWallet.getName());
                         getWallet().store();
                         Log.d(TAG, "wallet stored: " + myWallet.getName());
+                        if (observer != null) observer.onWalletStored();
                     }
                 }
                 break;
@@ -351,6 +355,7 @@ public class WalletService extends Service {
         if (listener == null) {
             Log.d(TAG, "start() loadWallet");
             Wallet aWallet = loadWallet(walletName, walletPassword);
+            // TODO check aWallet and die gracefully if neccessary
             listener = new MyWalletListener(aWallet);
             listener.start();
             showProgress(100);
@@ -416,6 +421,8 @@ public class WalletService extends Service {
                 WalletManager.getInstance().close(wallet); // TODO close() failed?
                 wallet = null;
                 // 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;
diff --git a/app/src/main/java/com/m2049r/xmrwallet/util/Helper.java b/app/src/main/java/com/m2049r/xmrwallet/util/Helper.java
index 873c89f1..182daf57 100644
--- a/app/src/main/java/com/m2049r/xmrwallet/util/Helper.java
+++ b/app/src/main/java/com/m2049r/xmrwallet/util/Helper.java
@@ -18,10 +18,13 @@ package com.m2049r.xmrwallet.util;
 
 import android.Manifest;
 import android.app.Activity;
+import android.app.Dialog;
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.os.Environment;
 import android.util.Log;
+import android.view.WindowManager;
+import android.view.inputmethod.InputMethodManager;
 
 import com.m2049r.xmrwallet.R;
 
@@ -82,4 +85,26 @@ public class Helper {
         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);
+    }
 }
diff --git a/app/src/main/res/layout/gen_fragment.xml b/app/src/main/res/layout/gen_fragment.xml
new file mode 100644
index 00000000..f9e23b82
--- /dev/null
+++ b/app/src/main/res/layout/gen_fragment.xml
@@ -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>
diff --git a/app/src/main/res/layout/gen_review_fragment.xml b/app/src/main/res/layout/gen_review_fragment.xml
new file mode 100644
index 00000000..9332dc37
--- /dev/null
+++ b/app/src/main/res/layout/gen_review_fragment.xml
@@ -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>
diff --git a/app/src/main/res/layout/login_activity.xml b/app/src/main/res/layout/login_activity.xml
index 017e4013..6c2ccbef 100644
--- a/app/src/main/res/layout/login_activity.xml
+++ b/app/src/main/res/layout/login_activity.xml
@@ -1,4 +1,17 @@
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/fragment_container"
+<?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" />
\ No newline at end of file
+    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>
diff --git a/app/src/main/res/layout/login_fragment.xml b/app/src/main/res/layout/login_fragment.xml
index 5090c92e..bf234203 100644
--- a/app/src/main/res/layout/login_fragment.xml
+++ b/app/src/main/res/layout/login_fragment.xml
@@ -1,18 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:tools="http://schemas.android.com/tools"
     android:layout_width="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"
-    tools:context="com.m2049r.xmrwallet.LoginActivity">
+    android:orientation="vertical">
 
     <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
         xmlns:app="http://schemas.android.com/apk/res-auto"
-        xmlns:tools="http://schemas.android.com/tools"
         android:layout_width="match_parent"
         android:layout_height="wrap_content">
 
diff --git a/app/src/main/res/layout/wallet_activity.xml b/app/src/main/res/layout/wallet_activity.xml
index 017e4013..6c2ccbef 100644
--- a/app/src/main/res/layout/wallet_activity.xml
+++ b/app/src/main/res/layout/wallet_activity.xml
@@ -1,4 +1,17 @@
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/fragment_container"
+<?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" />
\ No newline at end of file
+    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>
diff --git a/app/src/main/res/layout/wallet_fragment.xml b/app/src/main/res/layout/wallet_fragment.xml
index 7c80acd9..2a2e5789 100644
--- a/app/src/main/res/layout/wallet_fragment.xml
+++ b/app/src/main/res/layout/wallet_fragment.xml
@@ -1,16 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:tools="http://schemas.android.com/tools"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:background="@android:color/white"
-    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:orientation="vertical">
 
-    <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:tools="http://schemas.android.com/tools"
         android:layout_width="match_parent"
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index f2c64603..9ec235a0 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -11,14 +11,16 @@
     <string name="status_walletlist_loading">Loading Wallet List</string>
     <string name="status_wallet_loading">Loading Wallet &#8230;</string>
     <string name="status_wallet_unloading">Saving Wallet</string>
+    <string name="status_wallet_unloaded">Wallet saved</string>
     <string name="status_wallet_connecting">Connecting &#8230;</string>
     <string name="status_working">Working on it &#8230;</string>
 
     <string name="prompt_password">Password for</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_wrong_net">Daemon type does not fit to wallet!</string>
-    <string name="warn_daemon_unavailable">Cannot connect to daemon!</string>
+    <string name="prompt_wrong_net">Wallet does not match selected net</string>
+    <string name="warn_daemon_unavailable">Cannot connect to daemon! Try again.</string>
     <string name="panic">Something\'s wrong!</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_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">&lt;Watch Only Wallet&gt;</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>