wallet archive/backup

This commit is contained in:
m2049r 2017-09-03 14:09:27 +02:00
parent 20e7d6d065
commit ec7798cb34
7 changed files with 143 additions and 61 deletions

View File

@ -154,7 +154,7 @@ public class LoginActivity extends AppCompatActivity
@Override @Override
public void onWalletRename(String walletName) { public void onWalletRename(String walletName) {
Log.d(TAG, "rename for wallet ." + walletName + "."); Log.d(TAG, "rename for wallet ." + walletName + ".");
final File walletFile = Helper.getWalletFile(LoginActivity.this, walletName); final File walletFile = Helper.getWalletFile(this, walletName);
LayoutInflater li = LayoutInflater.from(this); LayoutInflater li = LayoutInflater.from(this);
View promptsView = li.inflate(R.layout.prompt_rename, null); View promptsView = li.inflate(R.layout.prompt_rename, null);
@ -174,7 +174,9 @@ public class LoginActivity extends AppCompatActivity
public void onClick(DialogInterface dialog, int id) { public void onClick(DialogInterface dialog, int id) {
Helper.hideKeyboardAlways(LoginActivity.this); Helper.hideKeyboardAlways(LoginActivity.this);
String newName = etRename.getText().toString(); String newName = etRename.getText().toString();
renameWallet(walletFile, newName); //TODO error if (!renameWallet(walletFile, newName)) {
Toast.makeText(LoginActivity.this, getString(R.string.rename_failed), Toast.LENGTH_LONG).show();
}
reloadWalletList(); reloadWalletList();
} }
}) })
@ -196,7 +198,9 @@ public class LoginActivity extends AppCompatActivity
Helper.hideKeyboardAlways(LoginActivity.this); Helper.hideKeyboardAlways(LoginActivity.this);
String newName = etRename.getText().toString(); String newName = etRename.getText().toString();
dialog.cancel(); dialog.cancel();
renameWallet(walletFile, newName); //TODO error if (!renameWallet(walletFile, newName)) {
Toast.makeText(LoginActivity.this, getString(R.string.rename_failed), Toast.LENGTH_LONG).show();
}
reloadWalletList(); reloadWalletList();
return false; return false;
} }
@ -207,6 +211,63 @@ public class LoginActivity extends AppCompatActivity
dialog.show(); dialog.show();
} }
@Override
public boolean onWalletBackup(String walletName) {
Log.d(TAG, "backup for wallet ." + walletName + ".");
File backupFolder = new File(getStorageRoot(), ".backups");
if (!backupFolder.exists()) {
if (!backupFolder.mkdir()) {
Log.e(TAG, "Cannot create backup dir " + backupFolder.getAbsolutePath());
return false;
}
}
File walletFile = Helper.getWalletFile(this, walletName);
File backupFile = new File(backupFolder, walletName);
Log.d(TAG, "backup " + walletFile.getAbsolutePath() + " to " + backupFile.getAbsolutePath());
if (copyWallet(walletFile, backupFile, true)) {
Toast.makeText(this, getString(R.string.backup_success), Toast.LENGTH_SHORT).show();
return true;
} else {
Toast.makeText(this, getString(R.string.backup_failed), Toast.LENGTH_LONG).show();
return false;
}
}
@Override
public void onWalletArchive(final String walletName) {
Log.d(TAG, "archive for wallet ." + walletName + ".");
DialogInterface.OnClickListener dialogClickListener = new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
switch (which) {
case DialogInterface.BUTTON_POSITIVE:
if (onWalletBackup(walletName)) {
if (deleteWallet(Helper.getWalletFile(LoginActivity.this, walletName))) {
Toast.makeText(LoginActivity.this, getString(R.string.archive_success), Toast.LENGTH_SHORT).show();
reloadWalletList();
} else {
Toast.makeText(LoginActivity.this, getString(R.string.delete_failed), Toast.LENGTH_LONG).show();
}
} else {
Toast.makeText(LoginActivity.this, getString(R.string.backup_failed), Toast.LENGTH_LONG).show();
}
break;
case DialogInterface.BUTTON_NEGATIVE:
// do nothing
break;
}
}
};
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage(getString(R.string.archive_alert_message))
.setTitle(walletName)
.setPositiveButton(getString(R.string.archive_alert_yes), dialogClickListener)
.setNegativeButton(getString(R.string.archive_alert_no), dialogClickListener)
.show();
}
void reloadWalletList() { void reloadWalletList() {
try { try {
LoginFragment loginFragment = (LoginFragment) LoginFragment loginFragment = (LoginFragment)
@ -532,7 +593,7 @@ public class LoginActivity extends AppCompatActivity
final File newWalletFile = new File(new File(getStorageRoot(), ".new"), name); final File newWalletFile = new File(new File(getStorageRoot(), ".new"), name);
final File walletFolder = getStorageRoot(); final File walletFolder = getStorageRoot();
final File walletFile = new File(walletFolder, name); final File walletFile = new File(walletFolder, name);
final boolean rc = copyWallet(newWalletFile, walletFile) final boolean rc = copyWallet(newWalletFile, walletFile, false)
&& &&
(testWallet(walletFile.getAbsolutePath(), password) == Wallet.Status.Status_Ok); (testWallet(walletFile.getAbsolutePath(), password) == Wallet.Status.Status_Ok);
if (rc) { if (rc) {
@ -557,7 +618,7 @@ public class LoginActivity extends AppCompatActivity
} }
boolean renameWallet(File walletFile, String newName) { boolean renameWallet(File walletFile, String newName) {
if (copyWallet(walletFile, new File(walletFile.getParentFile(), newName))) { if (copyWallet(walletFile, new File(walletFile.getParentFile(), newName), false)) {
deleteWallet(walletFile); deleteWallet(walletFile);
return true; return true;
} else { } else {
@ -565,7 +626,20 @@ public class LoginActivity extends AppCompatActivity
} }
} }
boolean copyWallet(File srcWallet, File dstWallet) { boolean walletExists(File walletFile) {
File dir = walletFile.getParentFile();
String name = walletFile.getName();
boolean exists = new File(dir, name).exists();
exists = new File(dir, name + ".keys").exists() && exists;
exists = new File(dir, name + ".address.txt").exists() && exists;
return exists;
}
boolean copyWallet(File srcWallet, File dstWallet, boolean overwrite) {
Log.d(TAG, "src=" + srcWallet.exists() + " dst=" + dstWallet.exists());
if (walletExists(dstWallet) && !overwrite) return false;
if (!walletExists(srcWallet)) return false;
boolean success = false; boolean success = false;
File srcDir = srcWallet.getParentFile(); File srcDir = srcWallet.getParentFile();
String srcName = srcWallet.getName(); String srcName = srcWallet.getName();
@ -586,6 +660,7 @@ public class LoginActivity extends AppCompatActivity
// do our best to delete as much as possible of the wallet files // do our best to delete as much as possible of the wallet files
boolean deleteWallet(File walletFile) { boolean deleteWallet(File walletFile) {
Log.d(TAG, "deleteWallet " + walletFile.getAbsolutePath());
if (!walletFile.isFile()) return false; if (!walletFile.isFile()) return false;
File dir = walletFile.getParentFile(); File dir = walletFile.getParentFile();
String name = walletFile.getName(); String name = walletFile.getName();
@ -596,12 +671,6 @@ public class LoginActivity extends AppCompatActivity
} }
void copyFile(File src, File dst) throws IOException { void copyFile(File src, File dst) throws IOException {
if (dst.exists()) {
throw new IOException("Destination exists!");
}
if (!src.exists()) {
throw new IOException("Source does not exist!");
}
FileChannel inChannel = new FileInputStream(src).getChannel(); FileChannel inChannel = new FileInputStream(src).getChannel();
FileChannel outChannel = new FileOutputStream(dst).getChannel(); FileChannel outChannel = new FileOutputStream(dst).getChannel();
try { try {

View File

@ -20,6 +20,7 @@ import android.content.Context;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.os.Bundle; import android.os.Bundle;
import android.os.StrictMode; import android.os.StrictMode;
import android.support.annotation.NonNull;
import android.support.design.widget.FloatingActionButton; import android.support.design.widget.FloatingActionButton;
import android.support.v4.app.Fragment; import android.support.v4.app.Fragment;
import android.util.Log; import android.util.Log;
@ -90,6 +91,10 @@ public class LoginFragment extends Fragment {
void onWalletRename(String name); void onWalletRename(String name);
boolean onWalletBackup(String name);
void onWalletArchive(String walletName);
void onAddWallet(); void onAddWallet();
void setTitle(String title); void setTitle(String title);
@ -389,20 +394,25 @@ public class LoginFragment extends Fragment {
public boolean onContextItemSelected(MenuItem item) { public boolean onContextItemSelected(MenuItem item) {
AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo(); AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
String listItem = (String) listView.getItemAtPosition(info.position); String listItem = (String) listView.getItemAtPosition(info.position);
String name = nameFromListItem(listItem, !isMainNet());
if (name == null) {
Toast.makeText(getActivity(), getString(R.string.panic), Toast.LENGTH_LONG).show();
}
switch (item.getItemId()) { switch (item.getItemId()) {
case R.id.action_info: case R.id.action_info:
showInfo(listItem); showInfo(name);
break; break;
case R.id.action_receive: case R.id.action_receive:
showReceive(listItem); showReceive(name);
break; break;
case R.id.action_rename: case R.id.action_rename:
String name = nameFromListItem(listItem, !isMainNet());
if (name != null) {
activityCallback.onWalletRename(name); activityCallback.onWalletRename(name);
} else { break;
// TODO do we say something here? case R.id.action_backup:
} activityCallback.onWalletBackup(name);
break;
case R.id.action_archive:
activityCallback.onWalletArchive(name);
break; break;
default: default:
return super.onContextItemSelected(item); return super.onContextItemSelected(item);
@ -410,37 +420,16 @@ public class LoginFragment extends Fragment {
return true; return true;
} }
private void showInfo(String listItem) { private void showInfo(@NonNull String name) {
if (listItem.length() <= (WALLETNAME_PREAMBLE_LENGTH)) {
Toast.makeText(getActivity(), getString(R.string.panic), Toast.LENGTH_LONG).show();
}
String wallet = listItem.substring(WALLETNAME_PREAMBLE_LENGTH);
String x = isMainNet() ? "4" : "9A";
if (x.indexOf(listItem.charAt(1)) < 0) {
Toast.makeText(getActivity(), getString(R.string.prompt_wrong_net), Toast.LENGTH_LONG).show();
}
checkAndSetWalletDaemon("", !isMainNet()); // just set selected net checkAndSetWalletDaemon("", !isMainNet()); // just set selected net
activityCallback.onWalletDetails(wallet); activityCallback.onWalletDetails(name);
}
private boolean showReceive(String listItem) {
if (listItem.length() <= (WALLETNAME_PREAMBLE_LENGTH)) {
Toast.makeText(getActivity(), getString(R.string.panic), Toast.LENGTH_LONG).show();
return true;
}
String wallet = nameFromListItem(listItem, !isMainNet());
if (wallet == null) {
Toast.makeText(getActivity(), getString(R.string.prompt_wrong_net), Toast.LENGTH_LONG).show();
return true;
} }
private boolean showReceive(@NonNull String name) {
checkAndSetWalletDaemon("", !isMainNet()); // just set selected net checkAndSetWalletDaemon("", !isMainNet()); // just set selected net
activityCallback.onWalletReceive(wallet); activityCallback.onWalletReceive(name);
return true; return true;
} }

View File

@ -79,8 +79,6 @@ public class ReceiveFragment extends Fragment {
etPaymentId.setRawInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS); etPaymentId.setRawInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
etDummy.setRawInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS); etDummy.setRawInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
Helper.showKeyboard(getActivity());
etPaymentId.requestFocus();
etPaymentId.setOnEditorActionListener(new TextView.OnEditorActionListener() { etPaymentId.setOnEditorActionListener(new TextView.OnEditorActionListener() {
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
if ((event != null && (event.getKeyCode() == KeyEvent.KEYCODE_ENTER)) || (actionId == EditorInfo.IME_ACTION_NEXT)) { if ((event != null && (event.getKeyCode() == KeyEvent.KEYCODE_ENTER)) || (actionId == EditorInfo.IME_ACTION_NEXT)) {
@ -114,7 +112,7 @@ public class ReceiveFragment extends Fragment {
etAmount.setOnEditorActionListener(new TextView.OnEditorActionListener() { etAmount.setOnEditorActionListener(new TextView.OnEditorActionListener() {
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
if ((event != null && (event.getKeyCode() == KeyEvent.KEYCODE_ENTER)) || (actionId == EditorInfo.IME_ACTION_NEXT)) { if ((event != null && (event.getKeyCode() == KeyEvent.KEYCODE_ENTER)) || (actionId == EditorInfo.IME_ACTION_DONE)) {
if (paymentIdOk() && amountOk()) { if (paymentIdOk() && amountOk()) {
Helper.hideKeyboard(getActivity()); Helper.hideKeyboard(getActivity());
generateQr(); generateQr();
@ -189,8 +187,9 @@ public class ReceiveFragment extends Fragment {
} }
} }
private void show(final String address) {
private void show(String address) { getActivity().runOnUiThread(new Runnable() {
public void run() {
tvAddress.setText(address); tvAddress.setText(address);
etPaymentId.setEnabled(true); etPaymentId.setEnabled(true);
etAmount.setEnabled(true); etAmount.setEnabled(true);
@ -199,6 +198,8 @@ public class ReceiveFragment extends Fragment {
hideProgress(); hideProgress();
generateQr(); generateQr();
} }
});
}
private void show(final String walletPath, final String password) { private void show(final String walletPath, final String password) {
new Thread(null, new Thread(null,
@ -208,8 +209,9 @@ public class ReceiveFragment extends Fragment {
final Wallet wallet = WalletManager.getInstance().openWallet(walletPath, password); final Wallet wallet = WalletManager.getInstance().openWallet(walletPath, password);
getActivity().runOnUiThread(new Runnable() { getActivity().runOnUiThread(new Runnable() {
public void run() { public void run() {
show(wallet.getAddress()); String address = wallet.getAddress();
wallet.close(); wallet.close();
show(address);
} }
}); });
} }
@ -259,6 +261,7 @@ public class ReceiveFragment extends Fragment {
etAmount.setText(amount); etAmount.setText(amount);
qrCode.setImageBitmap(qr); qrCode.setImageBitmap(qr);
etDummy.requestFocus(); etDummy.requestFocus();
bGenerate.setEnabled(false);
} }
} }

View File

@ -137,7 +137,6 @@
android:id="@+id/tvWalletSpendKey" android:id="@+id/tvWalletSpendKey"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:selectAllOnFocus="true"
android:textAlignment="center" android:textAlignment="center"
android:textColor="@color/colorPrimaryDark" android:textColor="@color/colorPrimaryDark"
android:textIsSelectable="true" android:textIsSelectable="true"

View File

@ -90,7 +90,7 @@
android:layout_weight="7" android:layout_weight="7"
android:enabled="false" android:enabled="false"
android:hint="@string/receive_amount_hint" android:hint="@string/receive_amount_hint"
android:imeOptions="actionNext" android:imeOptions="actionDone"
android:inputType="numberDecimal" android:inputType="numberDecimal"
android:textAlignment="textStart" android:textAlignment="textStart"
android:textSize="24sp" /> android:textSize="24sp" />

View File

@ -3,14 +3,24 @@
<item <item
android:id="@+id/action_info" android:id="@+id/action_info"
android:icon="@drawable/ic_info_black_24dp"
android:title="@string/menu_info" /> android:title="@string/menu_info" />
<item <item
android:id="@+id/action_receive" android:id="@+id/action_receive"
android:icon="@drawable/ic_monero_qr_24dp"
android:title="@string/menu_receive" /> android:title="@string/menu_receive" />
<item <item
android:id="@+id/action_rename" android:id="@+id/action_rename"
android:title="@string/menu_rename" /> android:title="@string/menu_rename" />
<item
android:id="@+id/action_backup"
android:title="@string/menu_backup" />
<item
android:id="@+id/action_archive"
android:title="@string/menu_archive" />
</menu> </menu>

View File

@ -4,8 +4,16 @@
<string name="wallet_activity_name">Wallet</string> <string name="wallet_activity_name">Wallet</string>
<string name="menu_info">Details</string> <string name="menu_info">Details</string>
<string name="menu_receive">Receive</string> <string name="menu_receive">QR Receive</string>
<string name="menu_rename">Rename</string> <string name="menu_rename">Rename</string>
<string name="menu_archive">Archive</string>
<string name="menu_backup">Backup</string>
<string name="backup_success">Backup successful</string>
<string name="backup_failed">Backup failed!</string>
<string name="archive_success">Archive successful</string>
<string name="delete_failed">Delete failed!</string>
<string name="rename_failed">Rename failed!</string>
<string name="prompt_daemon">[&lt;user&gt;:&lt;pass&gt;@]&lt;daemon&gt;[:&lt;port&gt;]</string> <string name="prompt_daemon">[&lt;user&gt;:&lt;pass&gt;@]&lt;daemon&gt;[:&lt;port&gt;]</string>
<string name="prompt_mainnet">Net Selection</string> <string name="prompt_mainnet">Net Selection</string>
@ -166,6 +174,10 @@
<string name="details_alert_yes">I\'m safe</string> <string name="details_alert_yes">I\'m safe</string>
<string name="details_alert_no">Take me back!</string> <string name="details_alert_no">Take me back!</string>
<string name="archive_alert_message">The wallet will be backuped up and then deleted!</string>
<string name="archive_alert_yes">Yes, do that!</string>
<string name="archive_alert_no">No thanks!</string>
<string name="big_amount">999999.999999999999</string> <string name="big_amount">999999.999999999999</string>
<string-array name="mixin"> <string-array name="mixin">