diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..5863481 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,4 @@ +## 1.0.12 + +* Added an abstraction to implement a daily backup. +* Added an implementation of that abstraction to upload a daily backup to your Google Drive by first authenticating into it. \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 8198138..4ee3ba7 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -10,7 +10,7 @@ android { minSdk 26 targetSdk 32 versionCode 14 - versionName "1.0.11" + versionName "1.0.12" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } @@ -28,6 +28,19 @@ android { buildFeatures { viewBinding true } + packagingOptions { + exclude 'META-INF/DEPENDENCIES' + } + signingConfigs { + debug { + v1SigningEnabled true + v2SigningEnabled true + } + release { + v1SigningEnabled true + v2SigningEnabled true + } + } } dependencies { @@ -51,7 +64,20 @@ dependencies { implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.4.1' implementation 'androidx.navigation:navigation-fragment:2.4.2' implementation 'androidx.navigation:navigation-ui:2.4.2' + implementation 'com.google.android.gms:play-services-auth:20.2.0' testImplementation 'junit:junit:4.13.2' androidTestImplementation 'androidx.test.ext:junit:1.1.3' androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' + + // Google Drive + implementation('com.google.api-client:google-api-client-android:1.33.0') { + exclude group: 'org.apache.httpcomponents' + exclude module: 'guava-jdk5' + } + implementation 'com.google.oauth-client:google-oauth-client-jetty:1.32.1' + implementation('com.google.apis:google-api-services-drive:v3-rev20211107-1.32.1') { + exclude group: 'org.apache.httpcomponents' + exclude module: 'guava-jdk5' + } + implementation 'com.google.http-client:google-http-client-jackson:1.15.0-rc' } \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 72cd8fe..6dffda1 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -26,6 +26,7 @@ android:largeHeap="true" android:persistent="true" + android:name=".MinimaApplication" android:dataExtractionRules="@xml/data_extraction_rules" android:fullBackupContent="@xml/backup_rules" android:icon="@drawable/ic_minima" @@ -97,6 +98,10 @@ + + + + oAuth2ResultLauncher); + + /** + * @param context Context of the application (resources wise) + * @return user's state and possible info depending on the provider injected + */ + public abstract void getUserState(Context context, BackupUserStateCallback backupUserStateCallback); + + /** + * @param context Context of the application (resources wise) + * @param fileToUpload File from the file system to upload. + * @param retryResultLauncher [ActivityResultLauncher] that will handle the + * and launch in case the user needs to do any + * further operation. + *

+ * Example: when the user denies the access of this + * app to Google Drive once accepted before. + *

+ * This parameter can be null, which means that it + * won't try to retry any OAuth2 further action that + * can be need, and it's usually null when we can to + * do a silent upload. + */ + public abstract void uploadBackup(Context context, java.io.File fileToUpload, @Nullable ActivityResultLauncher retryResultLauncher); + + /** + * @param context Context of the application (resources wise) + * @param fileToUpload File from the file system to upload. + */ + public void uploadBackup(Context context, java.io.File fileToUpload) { + uploadBackup(context, fileToUpload, null); + } + + // Providers + public static BackupSyncProvider getGoogleDriveProvider(Context context) { + return GoogleDriveProvider.getInstance(context); + } +} diff --git a/app/src/main/java/com/minima/android/dependencies/backupSync/minima/MinimaBackupUtils.java b/app/src/main/java/com/minima/android/dependencies/backupSync/minima/MinimaBackupUtils.java new file mode 100644 index 0000000..00ff2d5 --- /dev/null +++ b/app/src/main/java/com/minima/android/dependencies/backupSync/minima/MinimaBackupUtils.java @@ -0,0 +1,41 @@ +package com.minima.android.dependencies.backupSync.minima; + +import android.content.Context; + +import androidx.annotation.Nullable; + +import com.minima.android.service.MinimaService; + +import org.minima.Minima; +import org.minima.utils.MinimaLogger; + +import java.io.File; + +public class MinimaBackupUtils { + @Nullable + public static File createBackup(Context context) { + final Minima minima = MinimaService.minima; + if (minima != null) { + //Where are we going to store the file + String filename = "minima-backup.gz.bak"; + File backup = new File(context.getFilesDir(), filename); + if (backup.exists()) { + backup.delete(); + } + + //First run a command On Minima.. + String result = minima.runMinimaCMD("backup file:" + backup.getAbsolutePath()); + + //Now share this.. + MinimaLogger.log("Backup : " + result); + + if (backup.exists()) { + return backup; + } else { + return null; + } + } else { + return null; + } + } +} diff --git a/app/src/main/java/com/minima/android/dependencies/backupSync/model/BackupUserStateCallback.java b/app/src/main/java/com/minima/android/dependencies/backupSync/model/BackupUserStateCallback.java new file mode 100644 index 0000000..df2f169 --- /dev/null +++ b/app/src/main/java/com/minima/android/dependencies/backupSync/model/BackupUserStateCallback.java @@ -0,0 +1,5 @@ +package com.minima.android.dependencies.backupSync.model; + +public interface BackupUserStateCallback { + void onUserState(BackupUserStateModel backupUserStateModel); +} diff --git a/app/src/main/java/com/minima/android/dependencies/backupSync/model/BackupUserStateModel.java b/app/src/main/java/com/minima/android/dependencies/backupSync/model/BackupUserStateModel.java new file mode 100644 index 0000000..e6aeb03 --- /dev/null +++ b/app/src/main/java/com/minima/android/dependencies/backupSync/model/BackupUserStateModel.java @@ -0,0 +1,6 @@ +package com.minima.android.dependencies.backupSync.model; + +public abstract class BackupUserStateModel { +} + + diff --git a/app/src/main/java/com/minima/android/dependencies/backupSync/providers/drive/GoogleDriveProvider.java b/app/src/main/java/com/minima/android/dependencies/backupSync/providers/drive/GoogleDriveProvider.java new file mode 100644 index 0000000..6ec1983 --- /dev/null +++ b/app/src/main/java/com/minima/android/dependencies/backupSync/providers/drive/GoogleDriveProvider.java @@ -0,0 +1,225 @@ +package com.minima.android.dependencies.backupSync.providers.drive; + +import android.content.Context; +import android.content.Intent; + +import androidx.activity.result.ActivityResultLauncher; +import androidx.annotation.NonNull; + +import com.google.android.gms.auth.api.signin.GoogleSignIn; +import com.google.android.gms.auth.api.signin.GoogleSignInAccount; +import com.google.android.gms.auth.api.signin.GoogleSignInClient; +import com.google.android.gms.auth.api.signin.GoogleSignInOptions; +import com.google.android.gms.tasks.Task; +import com.google.api.client.googleapis.extensions.android.gms.auth.GoogleAccountCredential; +import com.google.api.client.googleapis.extensions.android.gms.auth.UserRecoverableAuthIOException; +import com.google.api.client.http.FileContent; +import com.google.api.client.http.javanet.NetHttpTransport; +import com.google.api.client.json.jackson.JacksonFactory; +import com.google.api.services.drive.Drive; +import com.google.api.services.drive.DriveScopes; +import com.google.api.services.drive.model.File; +import com.minima.android.dependencies.backupSync.BackupSyncProvider; +import com.minima.android.dependencies.backupSync.model.BackupUserStateCallback; +import com.minima.android.dependencies.backupSync.providers.drive.model.GoogleDriveServiceCallback; +import com.minima.android.dependencies.backupSync.providers.drive.model.fileModel.FolderCallback; +import com.minima.android.dependencies.backupSync.providers.drive.model.userModel.GoogleDriveUserNotSignedInYet; +import com.minima.android.dependencies.backupSync.providers.drive.model.userModel.GoogleDriveUserSignedInModel; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Optional; + +import javax.annotation.Nullable; + +public class GoogleDriveProvider extends BackupSyncProvider { + final GoogleSignInClient googleSignInClient; + + private GoogleDriveProvider(Context context) { + this.googleSignInClient = GoogleSignIn.getClient( + context, + new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN) + .requestEmail() + .build() + ); + } + + private static GoogleDriveProvider instance; + + public static GoogleDriveProvider getInstance(Context context) { + if (instance == null) { + instance = new GoogleDriveProvider(context); + } + + return instance; + } + + @Override + public void auth(Context context, @NonNull ActivityResultLauncher oAuth2ResultLauncher) { + Intent intent = createSignInIntent(); + oAuth2ResultLauncher.launch(intent); + } + + @Override + public void getUserState(Context context, BackupUserStateCallback backupUserStateCallback) { + final GoogleSignInAccount lastSignedInAccount = GoogleSignIn.getLastSignedInAccount(context); + if (lastSignedInAccount != null && !lastSignedInAccount.isExpired()) { + // send user already there + backupUserStateCallback.onUserState( + new GoogleDriveUserSignedInModel(lastSignedInAccount) + ); + } else { + // silent sign in + Task googleSignInAccountTask = googleSignInClient.silentSignIn(); + googleSignInAccountTask + .addOnSuccessListener(googleSignInAccount -> backupUserStateCallback.onUserState( + new GoogleDriveUserSignedInModel(googleSignInAccountTask.getResult()) + )) + .addOnFailureListener(e -> backupUserStateCallback.onUserState( + new GoogleDriveUserNotSignedInYet() + )); + } + } + + @Override + public void uploadBackup(Context context, java.io.File fileToUpload, @Nullable ActivityResultLauncher retry) { + getDriveService(context, driveService -> { + if (driveService != null) { + createFolderIfNeeded(context, retry, folderId -> { + // Specify file + final File gDriveFile = new File(); + final FileContent gDriveFileContent = new FileContent("application/gzip", fileToUpload); + gDriveFile.setName(fileToUpload.getName()); + gDriveFile.setParents(new ArrayList() {{ + add(folderId); + }}); + + // Take it to another thread + new Thread(() -> { + try { + // Find existing backup if needed + Optional fileFound = driveService.files().list() + .setQ("mimeType='application/gzip' and trashed=false") + .setSpaces("drive") + .setKey(context.getApplicationInfo().packageName) + .execute() + .getFiles() + .stream() + .findFirst(); + + final File id; + if (fileFound.isPresent()) { + // Update File + File file = fileFound.get(); + file.setParents(new ArrayList() {{ + add(folderId); + }}); + id = driveService + .files() + .update( + file.getId(), + null, + gDriveFileContent + ) + .execute(); + } else { + // Create file + id = driveService + .files() + .create(gDriveFile, gDriveFileContent) + .setFields("id") + .setKey(context.getApplicationInfo().packageName) + .execute(); + } + } catch (UserRecoverableAuthIOException e) { + if (retry != null) { + retry.launch(e.getIntent()); + } + } catch (IOException e) { + e.printStackTrace(); + } + }).start(); + }); + } + }); + } + + private void getDriveService(Context context, GoogleDriveServiceCallback googleDriveServiceCallback) { + getUserState(context, backupUserStateModel -> { + @Nullable final GoogleSignInAccount googleAccount; + if (backupUserStateModel instanceof GoogleDriveUserSignedInModel) { + googleAccount = ((GoogleDriveUserSignedInModel) backupUserStateModel).googleSignInAccount; + } else { + googleAccount = null; + } + + if (googleAccount != null) { + GoogleAccountCredential credential = GoogleAccountCredential.usingOAuth2(context, new ArrayList() {{ + add(DriveScopes.DRIVE_FILE); + }}); + + credential.setSelectedAccount(googleAccount.getAccount()); + + Drive.Builder builder = new Drive.Builder( + new NetHttpTransport(), + new JacksonFactory(), + credential + ); + builder.setApplicationName(applicationName); + googleDriveServiceCallback.onGoogleDriveServiceAvailable(builder.build()); + } else { + googleDriveServiceCallback.onGoogleDriveServiceAvailable(null); + } + }); + } + + private void createFolderIfNeeded(Context context, ActivityResultLauncher retry, FolderCallback folderCallback) { + getDriveService(context, driveService -> { + if (driveService != null) { + new Thread(() -> { + try { + // Find the previous folder we created + Optional folderFound = driveService.files().list() + .setQ("mimeType='application/vnd.google-apps.folder' and trashed=false") + .setSpaces("drive") + .setKey(context.getApplicationInfo().packageName) + .execute() + .getFiles() + .stream() + .findFirst(); + + if (folderFound.isPresent()) { + // Present this to the file creator + folderCallback.folderCreated(folderFound.get().getId()); + } else { + // Create folder + final File gDriveFolder = new File(); + gDriveFolder.setMimeType("application/vnd.google-apps.folder"); + gDriveFolder.setName(folderBackupName); + + File folderCreated = driveService + .files() + .create(gDriveFolder) + .setFields("id") + .setKey(context.getApplicationInfo().packageName) + .execute(); + folderCallback.folderCreated(folderCreated.getId()); + } + } catch (UserRecoverableAuthIOException e) { + retry.launch(e.getIntent()); + } catch (IOException e) { + e.printStackTrace(); + } + }).start(); + } + }); + } + + @NonNull + private Intent createSignInIntent() { + return googleSignInClient.getSignInIntent(); + } + + private static final String applicationName = "Minima GDrive"; + private static final String folderBackupName = "Minima Backup"; +} diff --git a/app/src/main/java/com/minima/android/dependencies/backupSync/providers/drive/model/GoogleDriveServiceCallback.java b/app/src/main/java/com/minima/android/dependencies/backupSync/providers/drive/model/GoogleDriveServiceCallback.java new file mode 100644 index 0000000..95a7864 --- /dev/null +++ b/app/src/main/java/com/minima/android/dependencies/backupSync/providers/drive/model/GoogleDriveServiceCallback.java @@ -0,0 +1,9 @@ +package com.minima.android.dependencies.backupSync.providers.drive.model; + +import com.google.api.services.drive.Drive; + +import javax.annotation.Nullable; + +public interface GoogleDriveServiceCallback { + void onGoogleDriveServiceAvailable(@Nullable Drive drive); +} diff --git a/app/src/main/java/com/minima/android/dependencies/backupSync/providers/drive/model/fileModel/FolderCallback.java b/app/src/main/java/com/minima/android/dependencies/backupSync/providers/drive/model/fileModel/FolderCallback.java new file mode 100644 index 0000000..e2292b4 --- /dev/null +++ b/app/src/main/java/com/minima/android/dependencies/backupSync/providers/drive/model/fileModel/FolderCallback.java @@ -0,0 +1,5 @@ +package com.minima.android.dependencies.backupSync.providers.drive.model.fileModel; + +public interface FolderCallback { + void folderCreated(String folderId); +} diff --git a/app/src/main/java/com/minima/android/dependencies/backupSync/providers/drive/model/userModel/GoogleDriveUserNotSignedInYet.java b/app/src/main/java/com/minima/android/dependencies/backupSync/providers/drive/model/userModel/GoogleDriveUserNotSignedInYet.java new file mode 100644 index 0000000..6731230 --- /dev/null +++ b/app/src/main/java/com/minima/android/dependencies/backupSync/providers/drive/model/userModel/GoogleDriveUserNotSignedInYet.java @@ -0,0 +1,4 @@ +package com.minima.android.dependencies.backupSync.providers.drive.model.userModel; + +public class GoogleDriveUserNotSignedInYet extends GoogleStateUserModel { +} diff --git a/app/src/main/java/com/minima/android/dependencies/backupSync/providers/drive/model/userModel/GoogleDriveUserSignedInModel.java b/app/src/main/java/com/minima/android/dependencies/backupSync/providers/drive/model/userModel/GoogleDriveUserSignedInModel.java new file mode 100644 index 0000000..d3723e5 --- /dev/null +++ b/app/src/main/java/com/minima/android/dependencies/backupSync/providers/drive/model/userModel/GoogleDriveUserSignedInModel.java @@ -0,0 +1,15 @@ +package com.minima.android.dependencies.backupSync.providers.drive.model.userModel; + +import com.google.android.gms.auth.api.signin.GoogleSignInAccount; + +public class GoogleDriveUserSignedInModel extends GoogleStateUserModel { + final public GoogleSignInAccount googleSignInAccount; + + public GoogleDriveUserSignedInModel(GoogleSignInAccount googleSignInAccount) { + this.googleSignInAccount = googleSignInAccount; + } + + public String getEmail() { + return googleSignInAccount.getEmail(); + } +} diff --git a/app/src/main/java/com/minima/android/dependencies/backupSync/providers/drive/model/userModel/GoogleStateUserModel.java b/app/src/main/java/com/minima/android/dependencies/backupSync/providers/drive/model/userModel/GoogleStateUserModel.java new file mode 100644 index 0000000..7bcac41 --- /dev/null +++ b/app/src/main/java/com/minima/android/dependencies/backupSync/providers/drive/model/userModel/GoogleStateUserModel.java @@ -0,0 +1,8 @@ +package com.minima.android.dependencies.backupSync.providers.drive.model.userModel; + +import com.minima.android.dependencies.backupSync.model.BackupUserStateModel; + +public abstract class GoogleStateUserModel extends BackupUserStateModel { +} + + diff --git a/app/src/main/java/com/minima/android/dependencies/backupSync/recurring/BackupRecurringAlarmManager.java b/app/src/main/java/com/minima/android/dependencies/backupSync/recurring/BackupRecurringAlarmManager.java new file mode 100644 index 0000000..8ca0055 --- /dev/null +++ b/app/src/main/java/com/minima/android/dependencies/backupSync/recurring/BackupRecurringAlarmManager.java @@ -0,0 +1,50 @@ +package com.minima.android.dependencies.backupSync.recurring; + +import android.app.AlarmManager; +import android.app.PendingIntent; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.os.Build; + +import com.minima.android.dependencies.backupSync.BackupSyncProvider; +import com.minima.android.dependencies.backupSync.minima.MinimaBackupUtils; + +public class BackupRecurringAlarmManager extends BroadcastReceiver { + @Override + public void onReceive(Context context, Intent intent) { + backup(context); + } + + private void backup(Context context) { + BackupSyncProvider + .getGoogleDriveProvider(context) + .uploadBackup( + context, + MinimaBackupUtils.createBackup(context) + ); + } + + public static void setAlarm(Context context) { + AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); + + Intent intent = new Intent(context, BackupRecurringAlarmManager.class); + + am.setInexactRepeating( + AlarmManager.RTC_WAKEUP, + System.currentTimeMillis(), + AlarmManager.INTERVAL_FIFTEEN_MINUTES, + createPendingIntent(context, intent) + ); + } + + private static PendingIntent createPendingIntent(Context context, Intent intent) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + return PendingIntent.getBroadcast(context, backupAlarmRequestCode, intent, PendingIntent.FLAG_IMMUTABLE); + } else { + return PendingIntent.getBroadcast(context, backupAlarmRequestCode, intent, 0); + } + } + + private static final int backupAlarmRequestCode = 10; +} diff --git a/app/src/main/java/com/minima/android/service/MinimaService.java b/app/src/main/java/com/minima/android/service/MinimaService.java index 7167770..24423b2 100644 --- a/app/src/main/java/com/minima/android/service/MinimaService.java +++ b/app/src/main/java/com/minima/android/service/MinimaService.java @@ -1,17 +1,14 @@ package com.minima.android.service; -import android.app.Activity; import android.app.Notification; import android.app.NotificationChannel; import android.app.NotificationManager; import android.app.PendingIntent; import android.app.Service; import android.content.BroadcastReceiver; -import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; -import android.content.SharedPreferences; import android.net.wifi.WifiManager; import android.os.BatteryManager; import android.os.Binder; @@ -24,8 +21,9 @@ import androidx.core.app.NotificationCompat; +import com.minima.android.MainActivity; + import org.minima.Minima; -import org.minima.objects.TxPoW; import org.minima.system.Main; import org.minima.system.network.webhooks.NotifyManager; import org.minima.utils.MinimaLogger; @@ -34,10 +32,6 @@ import org.minima.utils.messages.MessageListener; import java.util.ArrayList; -import java.util.Date; - -//import com.jraska.console.Console; -import com.minima.android.MainActivity; //import com.minima.android.R; //import com.minima.boot.Alarm; @@ -68,7 +62,7 @@ public MinimaService getService() { BroadcastReceiver mBatteryReceiver; //Minima Main Starter - Minima mStart; + public static Minima minima; //Used to update the Notification Handler mHandler; @@ -108,7 +102,7 @@ public void onCreate() { } //Start Minima - mStart = new Minima(); + minima = new Minima(); mHandler = new Handler(Looper.getMainLooper()); @@ -207,7 +201,7 @@ public void run() { //vars.add("35.228.18.150:9001"); //vars.add("10.0.2.2:9001"); - mStart.mainStarter(vars.toArray(new String[0])); + minima.mainStarter(vars.toArray(new String[0])); //Notify User service is now running! Toast.makeText(this, "Minima Service Started", Toast.LENGTH_SHORT).show(); @@ -217,7 +211,7 @@ public void run() { } public Minima getMinima(){ - return mStart; + return minima; } public Notification createNotification(String zText){ @@ -262,7 +256,7 @@ public void onDestroy() { MinimaLogger.log("Minima Service onDestroy start"); //QUIT nicely.. - String resp = mStart.runMinimaCMD("quit"); + String resp = minima.runMinimaCMD("quit"); //Not listening anymore.. Main.setMinimaListener(null); diff --git a/app/src/main/java/com/minima/android/ui/backup/BackupFragment.java b/app/src/main/java/com/minima/android/ui/backup/BackupFragment.java index aec1d7b..9273ded 100644 --- a/app/src/main/java/com/minima/android/ui/backup/BackupFragment.java +++ b/app/src/main/java/com/minima/android/ui/backup/BackupFragment.java @@ -1,27 +1,34 @@ package com.minima.android.ui.backup; +import android.app.Activity; +import android.content.Context; import android.content.Intent; import android.net.Uri; import android.os.Bundle; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; -import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.widget.Button; import android.widget.TextView; import android.widget.Toast; +import androidx.activity.result.ActivityResult; +import androidx.activity.result.ActivityResultCallback; +import androidx.activity.result.ActivityResultLauncher; +import androidx.activity.result.contract.ActivityResultContracts; import androidx.annotation.NonNull; import androidx.core.content.FileProvider; import androidx.fragment.app.Fragment; -import com.minima.android.BuildConfig; import com.minima.android.MainActivity; import com.minima.android.R; - -import org.minima.utils.MinimaLogger; +import com.minima.android.dependencies.backupSync.BackupSyncProvider; +import com.minima.android.dependencies.backupSync.minima.MinimaBackupUtils; +import com.minima.android.dependencies.backupSync.providers.drive.model.userModel.GoogleDriveUserNotSignedInYet; +import com.minima.android.dependencies.backupSync.providers.drive.model.userModel.GoogleDriveUserSignedInModel; +import com.minima.android.dependencies.backupSync.providers.drive.model.userModel.GoogleStateUserModel; import java.io.File; @@ -29,12 +36,25 @@ public class BackupFragment extends Fragment { MainActivity mMain; + private TextView gDriveText; + private Button gDriveButton; + + ActivityResultLauncher authResultLauncher = registerForActivityResult( + new ActivityResultContracts.StartActivityForResult(), + (ActivityResultCallback) result -> { + if (result.getResultCode() == Activity.RESULT_OK && getContext() != null) { + updateGDriveTexts(getContext()); + backup(getContext()); + } + } + ); + public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { setHasOptionsMenu(true); - mMain = (MainActivity)getActivity(); + mMain = (MainActivity) getActivity(); View root = inflater.inflate(R.layout.fragment_backup, container, false); @@ -51,49 +71,77 @@ public void onClick(View view) { restore.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { - Toast.makeText(mMain,"Restoring Minima.. pls wait",Toast.LENGTH_SHORT).show(); + Toast.makeText(mMain, "Restoring Minima.. pls wait", Toast.LENGTH_SHORT).show(); mMain.openFile(MainActivity.REQUEST_RESTORE); } }); + gDriveText = root.findViewById(R.id.text_gdrive); + gDriveButton = root.findViewById(R.id.backup_gdrive); + gDriveText.setVisibility(View.GONE); + gDriveButton.setVisibility(View.GONE); + + updateGDriveTexts(root.getContext()); + return root; } - public void makeBackup(){ - - Runnable bak = new Runnable() { - @Override - public void run() { - //Where are we going to store the file - String filename = "minima-backup.gz.bak"; - File backup = new File(mMain.getFilesDir(),filename); - if(backup.exists()){ - backup.delete(); - } + private void updateGDriveTexts(Context context) { + BackupSyncProvider + .getGoogleDriveProvider(context) + .getUserState(context, backupUserStateModel -> { + GoogleStateUserModel googleStateUserModel = (GoogleStateUserModel) backupUserStateModel; + + if (gDriveText != null && gDriveButton != null) { + gDriveText.setVisibility(View.VISIBLE); + gDriveButton.setVisibility(View.VISIBLE); + + if (googleStateUserModel instanceof GoogleDriveUserNotSignedInYet) { + gDriveText.setText(getString(R.string.minima_gdrive_backup_explanation_not_signed_in)); + gDriveButton.setText(getString(R.string.minima_gdrive_backup_button_not_signed_in)); + gDriveButton.setOnClickListener( + view -> BackupSyncProvider.getGoogleDriveProvider(context).auth(view.getContext(), authResultLauncher) + ); + } else if (googleStateUserModel instanceof GoogleDriveUserSignedInModel) { + gDriveText.setText( + getString( + R.string.minima_gdrive_backup_explanation_signed_in, + ((GoogleDriveUserSignedInModel) googleStateUserModel).getEmail() + ) + ); + gDriveButton.setText(getString(R.string.minima_gdrive_backup_button_signed_in)); + gDriveButton.setOnClickListener(view -> backup(view.getContext())); + } + } + }); - //First run a command On Minima.. - String result = mMain.getMinima().runMinimaCMD("backup file:"+backup.getAbsolutePath()); + } - //Now share this.. - MinimaLogger.log("Backup : "+result); + private void backup(Context context) { + BackupSyncProvider.getGoogleDriveProvider(context).uploadBackup(context, MinimaBackupUtils.createBackup(mMain), authResultLauncher); + } - if(backup.exists()) { - //Get the URi - Uri backupuri = FileProvider.getUriForFile(mMain,"com.minima.android.provider",backup); + public void makeBackup() { + Runnable bak = new Runnable() { + @Override + public void run() { + File backupFile = MinimaBackupUtils.createBackup(mMain); + if (backupFile != null) { + Uri backupUri = FileProvider.getUriForFile(mMain, minimaProviderAuthority, backupFile); //Now share that file.. Intent intentShareFile = new Intent(Intent.ACTION_SEND); intentShareFile.setType("application/zip"); - intentShareFile.putExtra(Intent.EXTRA_STREAM, backupuri); - intentShareFile.putExtra(Intent.EXTRA_SUBJECT,"Minima backup"); + intentShareFile.putExtra(Intent.EXTRA_STREAM, backupUri); + intentShareFile.putExtra(Intent.EXTRA_SUBJECT, "Minima backup"); intentShareFile.putExtra(Intent.EXTRA_TEXT, "Here is my Minima backup"); startActivity(Intent.createChooser(intentShareFile, "Store your Minima Backup")); - }else{ + } else { mMain.runOnUiThread(new Runnable() { @Override public void run() { - Toast.makeText(mMain,"Error creating backup..",Toast.LENGTH_LONG).show(); + Toast.makeText(mMain, "Error creating backup..", Toast.LENGTH_LONG).show(); } }); } @@ -109,4 +157,7 @@ public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { menu.clear(); super.onCreateOptionsMenu(menu, inflater); } + + private static final String minimaProviderAuthority = "com.minima.android.provider"; + } \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_backup.xml b/app/src/main/res/layout/fragment_backup.xml index e7d8c5a..127852e 100644 --- a/app/src/main/res/layout/fragment_backup.xml +++ b/app/src/main/res/layout/fragment_backup.xml @@ -1,6 +1,5 @@ + + +