Skip to content

Commit

Permalink
Merge pull request #95 from SecUSo/feature/Backup-Integration
Browse files Browse the repository at this point in the history
Feature/backup integration
  • Loading branch information
coderPaddyS authored Jan 13, 2023
2 parents 5348f91 + cb28ba8 commit ff4ce95
Show file tree
Hide file tree
Showing 72 changed files with 552 additions and 229 deletions.
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[submodule "libs/privacy-friendly-backup-api"]
path = libs/privacy-friendly-backup-api
url = https://github.com/SecUSo/privacy-friendly-backup-api.git
46 changes: 27 additions & 19 deletions app/build.gradle
Original file line number Diff line number Diff line change
@@ -1,18 +1,13 @@
apply plugin: 'com.android.application'
apply plugin: 'me.tatarka.retrolambda'
apply plugin: 'kotlin-android'

android {
compileSdkVersion 28

compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
compileSdkVersion 33

defaultConfig {
applicationId "privacyfriendlyshoppinglist.secuso.org.privacyfriendlyshoppinglist"
minSdkVersion 17
targetSdkVersion 26
minSdkVersion 23
targetSdkVersion 33
versionCode 7
versionName "1.0.9"
}
Expand Down Expand Up @@ -53,27 +48,27 @@ android {
}
}
}

dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
// android
androidTestImplementation 'com.android.support:support-annotations:28.0.0'
implementation 'com.android.support:appcompat-v7:28.0.0'
implementation 'com.android.support:design:28.0.0'
implementation 'com.android.support:support-v4:28.0.0'
implementation 'com.android.support:recyclerview-v7:28.0.0'
implementation 'com.android.support:cardview-v7:28.0.0'
androidTestImplementation 'androidx.annotation:annotation:1.0.0'
implementation 'androidx.appcompat:appcompat:1.0.0'
implementation 'com.google.android.material:material:1.0.0'
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
implementation 'androidx.recyclerview:recyclerview:1.0.0'
implementation 'androidx.cardview:cardview:1.0.0'

// tests
testImplementation 'junit:junit:4.12'
testImplementation 'org.mockito:mockito-core:2.7.6'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test:rules:1.0.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test:rules:1.1.1'
testImplementation 'pl.pragmatists:JUnitParams:0.3.6'
// dependency injection
implementation 'com.squareup.dagger:dagger:1.2.5'

annotationProcessor 'com.squareup.dagger:dagger-compiler:1.2.5'
compileOnly 'com.squareup.dagger:dagger-compiler:1.2.5'

// persistence
implementation 'com.j256.ormlite:ormlite-android:5.0'
// reactive x
Expand All @@ -85,4 +80,17 @@ dependencies {
implementation 'com.github.PhilJay:MPAndroidChart:v3.0.0-beta1'
// image zoom
implementation 'com.davemorrissey.labs:subsampling-scale-image-view:3.5.0'

implementation 'androidx.sqlite:sqlite:2.3.0'
implementation 'androidx.sqlite:sqlite-ktx:2.3.0'

// Backup API
implementation project(':backup-api')
def work_version = '2.7.1'
implementation "androidx.work:work-runtime:$work_version"
implementation "androidx.work:work-runtime-ktx:$work_version"
androidTestImplementation "androidx.work:work-testing:$work_version"

implementation 'androidx.core:core-ktx:1.7.20'
}

55 changes: 37 additions & 18 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="privacyfriendlyshoppinglist.secuso.org.privacyfriendlyshoppinglist">
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="privacyfriendlyshoppinglist.secuso.org.privacyfriendlyshoppinglist">

<uses-permission android:name="android.permission.CAMERA"/>
<uses-feature android:name="android.hardware.camera" android:required="false"/>
Expand All @@ -13,16 +15,18 @@
android:xlargeScreens="true"/>

<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
android:name=".PFAShoppingListApplication"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">

<activity
android:name=".ui.main.SplashActivity"
android:theme="@style/SplashTheme"
android:screenOrientation="portrait">
android:screenOrientation="portrait"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

Expand All @@ -38,16 +42,6 @@
android:configChanges="orientation|screenSize"
android:theme="@style/AppTheme.NoActionBar">
</activity>

<receiver
android:name='privacyfriendlyshoppinglist.secuso.org.privacyfriendlyshoppinglist.ui.shoppinglist.reminder.ReminderReceiver'>
</receiver>

<service
android:name='privacyfriendlyshoppinglist.secuso.org.privacyfriendlyshoppinglist.ui.shoppinglist.reminder.ReminderSchedulingService'>
</service>


<activity
android:name=".ui.products.ProductsActivity"
android:label="@string/activity_shopping_list"
Expand Down Expand Up @@ -136,6 +130,31 @@
android:name="android.support.PARENT_ACTIVITY"
android:value=".ui.main.MainActivity"/>
</activity>

<service
android:name=".backup.PFABackupService"
android:enabled="true"
android:exported="true"
android:process=":backup"
tools:ignore="ExportedService">
<intent-filter>
<action
android:name="org.secuso.privacyfriendlybackup.api.pfa.PFAAuthService" />
</intent-filter>
</service>

<receiver
android:name='privacyfriendlyshoppinglist.secuso.org.privacyfriendlyshoppinglist.ui.shoppinglist.reminder.ReminderReceiver'>
</receiver>

<service
android:name='privacyfriendlyshoppinglist.secuso.org.privacyfriendlyshoppinglist.ui.shoppinglist.reminder.ReminderSchedulingService'>
</service>

<provider
android:name="androidx.startup.InitializationProvider"
android:authorities="${applicationId}.androidx-startup"
tools:node="remove" />
</application>

</manifest>
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package privacyfriendlyshoppinglist.secuso.org.privacyfriendlyshoppinglist


import android.app.Application
import android.util.Log
import androidx.work.Configuration
import org.secuso.privacyfriendlybackup.api.pfa.BackupManager
import privacyfriendlyshoppinglist.secuso.org.privacyfriendlyshoppinglist.backup.BackupCreator
import privacyfriendlyshoppinglist.secuso.org.privacyfriendlyshoppinglist.backup.BackupRestorer

class PFAShoppingListApplication : Application(), Configuration.Provider {

override fun onCreate() {
super.onCreate()
BackupManager.backupCreator = BackupCreator()
BackupManager.backupRestorer = BackupRestorer()
}

override fun getWorkManagerConfiguration(): Configuration {
return Configuration.Builder().setMinimumLoggingLevel(Log.INFO).build()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package privacyfriendlyshoppinglist.secuso.org.privacyfriendlyshoppinglist.backup

import android.content.Context
import android.preference.PreferenceManager
import android.util.JsonWriter
import android.util.Log
import org.secuso.privacyfriendlybackup.api.backup.DatabaseUtil.getSupportSQLiteOpenHelper
import org.secuso.privacyfriendlybackup.api.backup.DatabaseUtil.writeDatabase
import org.secuso.privacyfriendlybackup.api.backup.PreferenceUtil.writePreferences
import org.secuso.privacyfriendlybackup.api.pfa.IBackupCreator
import privacyfriendlyshoppinglist.secuso.org.privacyfriendlyshoppinglist.framework.persistence.DB
import java.io.OutputStream
import java.io.OutputStreamWriter

class BackupCreator : IBackupCreator {
override fun writeBackup(context: Context, outputStream: OutputStream): Boolean {
Log.d(TAG, "createBackup() started")
val outputStreamWriter = OutputStreamWriter(outputStream, Charsets.UTF_8)
val writer = JsonWriter(outputStreamWriter)
writer.setIndent("")

try {
writer.beginObject()

Log.d(TAG, "Writing database")
writer.name("database")

val database = getSupportSQLiteOpenHelper(context, DB.APP.dbName).readableDatabase

writeDatabase(writer, database)
database.close()

Log.d(TAG, "Writing preferences")
writer.name("preferences")

val pref = PreferenceManager.getDefaultSharedPreferences(context.applicationContext)
writePreferences(writer, pref)

writer.endObject()
writer.close()
} catch (e: Exception) {
Log.e(TAG, "Error occurred", e)
e.printStackTrace()
return false
}

Log.d(TAG, "Backup created successfully")
return true
}

companion object {
const val TAG = "PFABackupCreator"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
package privacyfriendlyshoppinglist.secuso.org.privacyfriendlyshoppinglist.backup

import android.content.Context
import android.content.SharedPreferences
import android.preference.PreferenceManager
import android.util.JsonReader
import android.util.Log
import org.secuso.privacyfriendlybackup.api.backup.DatabaseUtil
import org.secuso.privacyfriendlybackup.api.backup.FileUtil
import org.secuso.privacyfriendlybackup.api.pfa.IBackupRestorer
import privacyfriendlyshoppinglist.secuso.org.privacyfriendlyshoppinglist.framework.persistence.DB
import java.io.IOException
import java.io.InputStream
import java.io.InputStreamReader
import kotlin.system.exitProcess


class BackupRestorer : IBackupRestorer {
@Throws(IOException::class)
private fun readDatabase(reader: JsonReader, context: Context) {
reader.beginObject()
val n1: String = reader.nextName()
if (n1 != "version") {
throw RuntimeException("Unknown value $n1")
}
val version: Int = reader.nextInt()
val n2: String = reader.nextName()
if (n2 != "content") {
throw RuntimeException("Unknown value $n2")
}

Log.d(TAG, "Restoring database...")
val restoreDatabaseName = "restoreDatabase"

// delete if file already exists
val restoreDatabaseFile = context.getDatabasePath(restoreDatabaseName)
if (restoreDatabaseFile.exists()) {
DatabaseUtil.deleteRoomDatabase(context, restoreDatabaseName)
}

// create new restore database
val db = DatabaseUtil.getSupportSQLiteOpenHelper(context, restoreDatabaseName, version).writableDatabase

db.beginTransaction()
db.version = version

Log.d(TAG, "Copying database contents...")
DatabaseUtil.readDatabaseContent(reader, db)
db.setTransactionSuccessful()
db.endTransaction()
db.close()

reader.endObject()

// copy file to correct location
val actualDatabaseFile = context.getDatabasePath(DB.APP.dbName)

DatabaseUtil.deleteRoomDatabase(context, DB.APP.dbName)

FileUtil.copyFile(restoreDatabaseFile, actualDatabaseFile)
Log.d(TAG, "Database Restored")

// delete restore database
DatabaseUtil.deleteRoomDatabase(context, restoreDatabaseName)
}

@Throws(IOException::class)
private fun readPreferences(reader: JsonReader, preferences: SharedPreferences.Editor) {
reader.beginObject()
while (reader.hasNext()) {
val name: String = reader.nextName()
when (name) {
"workoutMode",
"privacyfriendlyshoppinglist.secuso.org.privacyfriendlyshoppinglist.pref.sort_asc_dec_key" -> preferences.putBoolean(name, reader.nextBoolean())
"privacyfriendlyshoppinglist.secuso.org.privacyfriendlyshoppinglist.pref.sort_by_key" -> preferences.putString(name, reader.nextString())
else -> throw RuntimeException("Unknown preference $name")
}
}
reader.endObject()
}

private fun readPreferenceSet(reader: JsonReader): Set<String> {
val preferenceSet = mutableSetOf<String>()

reader.beginArray()
while (reader.hasNext()) {
preferenceSet.add(reader.nextString());
}
reader.endArray()
return preferenceSet
}

override fun restoreBackup(context: Context, restoreData: InputStream): Boolean {
return try {
val isReader = InputStreamReader(restoreData)
val reader = JsonReader(isReader)
val preferences = PreferenceManager.getDefaultSharedPreferences(context).edit()

// START
reader.beginObject()
while (reader.hasNext()) {
val type: String = reader.nextName()
when (type) {
"database" -> readDatabase(reader, context)
"preferences" -> readPreferences(reader, preferences)
else -> throw RuntimeException("Can not parse type $type")
}
}
reader.endObject()
preferences.commit()

exitProcess(0)
} catch (e: Exception) {
e.printStackTrace()
false
}
}

companion object {
const val TAG = "PFABackupRestorer"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package privacyfriendlyshoppinglist.secuso.org.privacyfriendlyshoppinglist.backup

import org.secuso.privacyfriendlybackup.api.pfa.PFAAuthService

class PFABackupService : PFAAuthService()
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package privacyfriendlyshoppinglist.secuso.org.privacyfriendlyshoppinglist.framework.ui;

import android.content.Context;
import android.support.v7.widget.RecyclerView;
import androidx.recyclerview.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package privacyfriendlyshoppinglist.secuso.org.privacyfriendlyshoppinglist.framework.ui;

import android.support.v7.widget.RecyclerView;
import android.view.View;

import androidx.recyclerview.widget.RecyclerView;

import privacyfriendlyshoppinglist.secuso.org.privacyfriendlyshoppinglist.framework.business.AbstractItem;
import privacyfriendlyshoppinglist.secuso.org.privacyfriendlyshoppinglist.framework.business.PFACache;

Expand Down
Loading

0 comments on commit ff4ce95

Please sign in to comment.