Export feature

You can now export (it's an early stage) your manual entries to a file to restore it later
- Choose where to put your backup
- Code for encrypting data (will be enabled soon)
- Update version number to 0.0.6
This commit is contained in:
Tanguy Herbron 2018-07-11 23:57:55 +02:00
parent de6fc36e6c
commit e173e48612
11 changed files with 182 additions and 51 deletions

Binary file not shown.

View File

@ -6,10 +6,15 @@ android {
applicationId "com.herbron.moodl" applicationId "com.herbron.moodl"
minSdkVersion 19 minSdkVersion 19
targetSdkVersion 27 targetSdkVersion 27
versionCode 5 versionCode 6
versionName "0.0.5" versionName "0.0.6"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
} }
dataBinding {
enabled = true
}
buildTypes { buildTypes {
release { release {
minifyEnabled false minifyEnabled false
@ -32,7 +37,7 @@ dependencies {
implementation 'com.android.support:cardview-v7:27.1.1' implementation 'com.android.support:cardview-v7:27.1.1'
implementation 'com.mcxiaoke.volley:library:1.0.19' implementation 'com.mcxiaoke.volley:library:1.0.19'
implementation 'com.diogobernardino:williamchart:2.5.0' implementation 'com.diogobernardino:williamchart:2.5.0'
implementation 'com.android.support.constraint:constraint-layout:1.1.0' implementation 'com.android.support.constraint:constraint-layout:1.1.2'
implementation 'com.android.support:support-v4:27.1.1' implementation 'com.android.support:support-v4:27.1.1'
implementation 'com.android.support:palette-v7:27.1.1' implementation 'com.android.support:palette-v7:27.1.1'
implementation 'com.daimajia.swipelayout:library:1.2.0@aar' implementation 'com.daimajia.swipelayout:library:1.2.0@aar'
@ -47,9 +52,11 @@ dependencies {
implementation 'com.mattprecious.swirl:swirl:1.1.0' implementation 'com.mattprecious.swirl:swirl:1.1.0'
implementation 'com.wdullaer:materialdatetimepicker:3.5.2' implementation 'com.wdullaer:materialdatetimepicker:3.5.2'
implementation 'com.jmedeisis:draglinearlayout:1.1.0' implementation 'com.jmedeisis:draglinearlayout:1.1.0'
implementation 'com.applandeo:material-file-picker:1.0.0'
testImplementation 'junit:junit:4.12' testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2' androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
implementation files('../libs/binance-api.jar') implementation files('../libs/binance-api.jar')
implementation files('../libs/commons-codec-1.11.jar');
} }

View File

@ -7,6 +7,7 @@ import android.app.Dialog;
import android.app.KeyguardManager; import android.app.KeyguardManager;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.content.res.Configuration; import android.content.res.Configuration;
@ -42,7 +43,12 @@ import android.widget.LinearLayout;
import android.widget.ProgressBar; import android.widget.ProgressBar;
import android.widget.TextView; import android.widget.TextView;
import com.applandeo.FilePicker;
import com.applandeo.constants.FileType;
import com.applandeo.listeners.OnSelectFileListener;
import com.herbron.moodl.BuildConfig; import com.herbron.moodl.BuildConfig;
import com.herbron.moodl.DataManagers.DataCrypter;
import com.herbron.moodl.DataManagers.DatabaseManager;
import com.herbron.moodl.FingerprintToolkit.FingerprintDialogFragment; import com.herbron.moodl.FingerprintToolkit.FingerprintDialogFragment;
import com.herbron.moodl.FingerprintToolkit.FingerprintHandler; import com.herbron.moodl.FingerprintToolkit.FingerprintHandler;
import com.herbron.moodl.MoodlBox; import com.herbron.moodl.MoodlBox;
@ -64,10 +70,10 @@ import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException; import java.security.cert.CertificateException;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.regex.Pattern;
import javax.crypto.Cipher; import javax.crypto.Cipher;
import javax.crypto.KeyGenerator; import javax.crypto.KeyGenerator;
@ -169,7 +175,7 @@ public class SettingsActivity extends AppCompatPreferenceActivity {
bindPreferenceSummaryToValue(findPreference("default_currency")); bindPreferenceSummaryToValue(findPreference("default_currency"));
bindPreferenceSummaryToValue(findPreference("minimum_value_displayed")); bindPreferenceSummaryToValue(findPreference("minimum_value_displayed"));
findPreference("import").setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { findPreference("export").setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
@Override @Override
public boolean onPreferenceClick(Preference preference) { public boolean onPreferenceClick(Preference preference) {
@ -178,7 +184,33 @@ public class SettingsActivity extends AppCompatPreferenceActivity {
View dialogView = LayoutInflater.from(context).inflate(R.layout.dialog_import_data, null, true); View dialogView = LayoutInflater.from(context).inflate(R.layout.dialog_import_data, null, true);
dialogBuilder.setView(dialogView); dialogBuilder.setView(dialogView);
CheckBox enterPasswordCheckbox = dialogView.findViewById(R.id.checkboxEnterPassword); File backupDirectory = new File(Environment.getExternalStorageDirectory(), getString(R.string.app_name));
if (!backupDirectory.exists()) {
if (!backupDirectory.mkdirs()) {
Log.d("moodl", "Error while creating directory");
}
}
final TextView textViewFilePath = dialogView.findViewById(R.id.textViewFilePath);
textViewFilePath.setText(backupDirectory.getAbsolutePath());
textViewFilePath.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
new FilePicker.Builder(SettingsActivity.this, new OnSelectFileListener() {
@Override
public void onSelect(File file) {
textViewFilePath.setText(file.getAbsolutePath());
}
}).fileType("moodl")
.hideFiles(true)
.directory(backupDirectory.getAbsolutePath())
.mainDirectory(Environment.getExternalStorageDirectory().getAbsolutePath())
.show();
}
});
final CheckBox enterPasswordCheckbox = dialogView.findViewById(R.id.checkboxEnterPassword);
final TextInputLayout textInputLayoutPassword = dialogView.findViewById(R.id.textInputLayoutPassword); final TextInputLayout textInputLayoutPassword = dialogView.findViewById(R.id.textInputLayoutPassword);
enterPasswordCheckbox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { enterPasswordCheckbox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@ -196,53 +228,33 @@ public class SettingsActivity extends AppCompatPreferenceActivity {
} }
}); });
dialogBuilder.setTitle("Restore backup"); dialogBuilder.setTitle("Create backup");
dialogBuilder.setPositiveButton("Confirm", new DialogInterface.OnClickListener() { dialogBuilder.setPositiveButton("Confirm", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) { public void onClick(DialogInterface dialog, int whichButton) {
checkPermissions(); checkPermissions();
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss", Locale.getDefault()); SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss", Locale.getDefault());
Date currentDate = new Date(); Date currentDate = new Date();
//String fileName = getString(R.string.app_name) + "_" + formatter.format(currentDate) + ".backup"; String fileName = getString(R.string.app_name) + "_" + formatter.format(currentDate) + ".backup";
String fileName = "backup.moodl"; DatabaseManager databaseManager = new DatabaseManager(SettingsActivity.this);
File dir = new File(Environment.getExternalStorageDirectory(), getString(R.string.app_name)); File backupFile = new File(textViewFilePath.getText() + "/" + fileName);
if (!dir.exists()) { try (PrintWriter printWriter = new PrintWriter(new FileWriter(backupFile, true))) {
if (!dir.mkdirs()) {
Log.d("moodl", "Error while creating directory"); if(enterPasswordCheckbox.isChecked())
{
DataCrypter.updateKey(textInputLayoutPassword.getEditText().getText().toString());
printWriter.write(DataCrypter.encrypt(SettingsActivity.this, databaseManager.getBackupData()));
} }
} else
{
File backupFile = new File(dir + "/" + fileName); printWriter.write(databaseManager.getBackupData());
if(backupFile.exists())
{
try (FileReader fileReader = new FileReader(backupFile)) {
BufferedReader bufferedReader = new BufferedReader(fileReader);
String line;
while((line = bufferedReader.readLine()) != null)
{
Log.d("moodl", line);
}
} catch (IOException e) {
Log.d("moodl", "Error > " + e);
} }
}
else
{
Log.d("moodl", "Not backup file found");
try (PrintWriter printWriter = new PrintWriter(new FileWriter(backupFile, true))) { printWriter.close();
} catch (IOException e) {
printWriter.write("Some data"); Log.d("moodl", "Error > " + e);
printWriter.close();
} catch (IOException e) {
Log.d("moodl", "Error > " + e);
}
} }
dialog.dismiss(); dialog.dismiss();

View File

@ -0,0 +1,66 @@
package com.herbron.moodl.DataManagers;
import android.content.Context;
import android.util.Log;
import com.herbron.moodl.R;
import org.apache.commons.codec.binary.Base64;
import java.io.UnsupportedEncodingException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
public class DataCrypter {
private static Key aesKey;
public static void updateKey(String key)
{
for(int i = 0; key.getBytes().length < 32; i++)
{
key += "0";
}
try {
aesKey = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
} catch (UnsupportedEncodingException e) {
Log.d("moodl", "Error while creating encryption key " + e.getMessage());
}
}
public static String encrypt(Context context, String data)
{
String encryptedData = null;
try {
IvParameterSpec ivParameterSpec = new IvParameterSpec(context.getString(R.string.ivKey).getBytes("UTF-8"));
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
cipher.init(Cipher.ENCRYPT_MODE, aesKey, ivParameterSpec);
byte[] encryptedBytes = cipher.doFinal(data.getBytes());
encryptedData = Base64.encodeBase64String(encryptedBytes);
} catch (NoSuchPaddingException | NoSuchAlgorithmException
| InvalidKeyException | BadPaddingException
| IllegalBlockSizeException | UnsupportedEncodingException
| InvalidAlgorithmParameterException e) {
Log.d("moodl", "Error while encrypting data " + e.getMessage());
}
return encryptedData;
}
}

View File

@ -144,11 +144,33 @@ public class DatabaseManager extends SQLiteOpenHelper{
return result.getInt(0); return result.getInt(0);
} }
public int deleteCurrencyFromWatchlist(String symbol) public void deleteCurrencyFromWatchlist(String symbol)
{ {
SQLiteDatabase db = this.getWritableDatabase(); SQLiteDatabase db = this.getWritableDatabase();
return db.delete(TABLE_WATCHLIST, KEY_WATCHLIST_SYMBOL + " = '" + symbol + "'", null); db.delete(TABLE_WATCHLIST, KEY_WATCHLIST_SYMBOL + " = '" + symbol + "'", null);
db.close();
}
public String getBackupData()
{
String selectQuerry = "SELECT * FROM " + TABLE_MANUAL_CURRENCIES;
SQLiteDatabase db = this.getWritableDatabase();
Cursor result = db.rawQuery(selectQuerry, null);
String backupData = "";
while(result.moveToNext())
{
for(int i = 0; i < result.getColumnCount(); i++)
{
backupData += result.getString(i) + ";@";
}
backupData += "\n";
}
return backupData;
} }
public List<Currency> getAllCurrenciesFromWatchlist() public List<Currency> getAllCurrenciesFromWatchlist()

View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8" ?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape android:shape="rectangle">
<solid android:color="@color/separationColor"/>
<corners android:radius="5dp"/>
<padding
android:left="3dp"
android:right="3dp"
android:top="3dp"
android:bottom="3dp"/>
</shape>
</item>
</selector>

View File

@ -9,6 +9,13 @@
android:padding="5dp" android:padding="5dp"
android:focusableInTouchMode="true"> android:focusableInTouchMode="true">
<TextView
android:id="@+id/textViewFilePath"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Click to select"
android:background="@drawable/background_filepath"/>
<CheckBox <CheckBox
android:id="@+id/checkboxConserveData" android:id="@+id/checkboxConserveData"
android:layout_width="match_parent" android:layout_width="match_parent"
@ -31,7 +38,8 @@
android:id="@+id/checkboxEnterPassword" android:id="@+id/checkboxEnterPassword"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="@string/enter_password"/> android:text="@string/enter_password"
android:enabled="false"/>
<android.support.design.widget.TextInputLayout <android.support.design.widget.TextInputLayout
android:id="@+id/textInputLayoutPassword" android:id="@+id/textInputLayoutPassword"

View File

@ -21,6 +21,8 @@
<string name="pref_title_version">Version</string> <string name="pref_title_version">Version</string>
<string name="ivKey">0123456789MoodlH</string> <!--Must be 16 characters-->
<string name="pref_title_export">Export manual entries</string> <string name="pref_title_export">Export manual entries</string>
<string name="pref_title_import">Import manual entries</string> <string name="pref_title_import">Import manual entries</string>

View File

@ -28,11 +28,11 @@
android:title="@string/pref_title_category_data_backup"> android:title="@string/pref_title_category_data_backup">
<PreferenceScreen android:title="@string/pref_title_export" <PreferenceScreen android:title="@string/pref_title_export"
android:key="export" android:key="export"/>
android:enabled="false"/>
<Preference android:title="@string/pref_title_import" <Preference android:title="@string/pref_title_import"
android:key="import"/> android:key="import"
android:enabled="false"/>
</PreferenceCategory> </PreferenceCategory>

View File

@ -19,9 +19,8 @@ allprojects {
repositories { repositories {
google() google()
jcenter() jcenter()
maven { maven { url "https://jitpack.io" }
url "https://jitpack.io" maven { url "http://dl.bintray.com/lukaville/maven" }
}
} }
} }

BIN
libs/commons-codec-1.11.jar Normal file

Binary file not shown.