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:
parent
de6fc36e6c
commit
e173e48612
BIN
.idea/caches/build_file_checksums.ser
generated
BIN
.idea/caches/build_file_checksums.ser
generated
Binary file not shown.
@ -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');
|
||||||
}
|
}
|
||||||
|
@ -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,54 +228,34 @@ 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()) {
|
|
||||||
if (!dir.mkdirs()) {
|
|
||||||
Log.d("moodl", "Error while creating directory");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
File backupFile = new File(dir + "/" + fileName);
|
|
||||||
|
|
||||||
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))) {
|
try (PrintWriter printWriter = new PrintWriter(new FileWriter(backupFile, true))) {
|
||||||
|
|
||||||
printWriter.write("Some data");
|
if(enterPasswordCheckbox.isChecked())
|
||||||
|
{
|
||||||
|
DataCrypter.updateKey(textInputLayoutPassword.getEditText().getText().toString());
|
||||||
|
printWriter.write(DataCrypter.encrypt(SettingsActivity.this, databaseManager.getBackupData()));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printWriter.write(databaseManager.getBackupData());
|
||||||
|
}
|
||||||
|
|
||||||
printWriter.close();
|
printWriter.close();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
Log.d("moodl", "Error > " + e);
|
Log.d("moodl", "Error > " + e);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
dialog.dismiss();
|
dialog.dismiss();
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
@ -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()
|
||||||
|
15
app/src/main/res/drawable/background_filepath.xml
Normal file
15
app/src/main/res/drawable/background_filepath.xml
Normal 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>
|
@ -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"
|
||||||
|
@ -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>
|
||||||
|
|
||||||
|
@ -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>
|
||||||
|
|
||||||
|
@ -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
BIN
libs/commons-codec-1.11.jar
Normal file
Binary file not shown.
Loading…
Reference in New Issue
Block a user