mirror of
https://github.com/yuliskov/SmartTube.git
synced 2025-12-30 18:40:27 -06:00
backup upd
This commit is contained in:
@@ -117,8 +117,10 @@ public class BackupSettingsPresenter extends BasePresenter<Void> {
|
||||
|
||||
BackupAndRestoreManager backupManager = new BackupAndRestoreManager(getContext());
|
||||
|
||||
String backupPath = backupManager.getBackupPathRoot();
|
||||
|
||||
options.add(UiOptionItem.from(
|
||||
String.format("%s:\n%s", getContext().getString(R.string.app_backup), backupManager.getBackupPath()),
|
||||
String.format("%s:\n%s", getContext().getString(R.string.app_backup), backupPath),
|
||||
option -> {
|
||||
AppDialogUtil.showConfirmationDialog(getContext(), getContext().getString(R.string.app_backup), () -> {
|
||||
mSidebarService.enableSection(MediaGroup.TYPE_SETTINGS, true); // prevent Settings lock
|
||||
@@ -127,9 +129,8 @@ public class BackupSettingsPresenter extends BasePresenter<Void> {
|
||||
});
|
||||
}));
|
||||
|
||||
String backupPathCheck = backupManager.getBackupPathCheck();
|
||||
options.add(UiOptionItem.from(
|
||||
String.format("%s:\n%s", getContext().getString(R.string.app_restore), backupPathCheck != null ? backupPathCheck : ""),
|
||||
String.format("%s:\n%s", getContext().getString(R.string.app_restore), backupPath),
|
||||
option -> {
|
||||
backupManager.getBackupNames(names -> showLocalRestoreDialog(backupManager, names));
|
||||
}));
|
||||
|
||||
@@ -0,0 +1,220 @@
|
||||
package com.liskovsoft.smartyoutubetv2.common.misc;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.os.Build.VERSION;
|
||||
import android.os.Environment;
|
||||
import android.provider.OpenableColumns;
|
||||
|
||||
import androidx.core.content.FileProvider;
|
||||
|
||||
import com.liskovsoft.smartyoutubetv2.common.misc.MotherActivity.OnResult;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipInputStream;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
public class BackupAndRestoreHelper implements OnResult {
|
||||
private static final int REQ_PICK_FILES = 1001;
|
||||
private final Context mContext;
|
||||
private Runnable mOnSuccess;
|
||||
|
||||
public BackupAndRestoreHelper(Context context) {
|
||||
mContext = context;
|
||||
}
|
||||
|
||||
public void exportAppMediaFolder() {
|
||||
if (VERSION.SDK_INT < 30) {
|
||||
return;
|
||||
}
|
||||
|
||||
File mediaDir = getExternalStorageDirectory();
|
||||
File dataDir = new File(mediaDir, "data");
|
||||
if (!dataDir.exists()) return;
|
||||
|
||||
File zipFile = new File(mediaDir, "backup.zip");
|
||||
zipDirectory(dataDir, zipFile);
|
||||
|
||||
Uri uri = FileProvider.getUriForFile(
|
||||
mContext,
|
||||
mContext.getPackageName() + ".update_provider",
|
||||
zipFile
|
||||
);
|
||||
|
||||
Intent intent = new Intent(Intent.ACTION_SEND);
|
||||
intent.setType("*/*");
|
||||
intent.putExtra(Intent.EXTRA_STREAM, uri);
|
||||
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
||||
mContext.startActivity(Intent.createChooser(intent, "Send to Total Commander"));
|
||||
}
|
||||
|
||||
public void importAppMediaFolder(Runnable onSuccess) {
|
||||
if (VERSION.SDK_INT < 30 || onSuccess == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
mOnSuccess = onSuccess;
|
||||
|
||||
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
|
||||
intent.setType("*/*");
|
||||
//intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
|
||||
|
||||
((MotherActivity) mContext).addOnResult(this);
|
||||
|
||||
((Activity) mContext).startActivityForResult(intent, REQ_PICK_FILES);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResult(int requestCode, int resultCode, Intent data) {
|
||||
if (requestCode == REQ_PICK_FILES && resultCode == Activity.RESULT_OK) {
|
||||
|
||||
if (data == null) return;
|
||||
|
||||
File mediaDir = getExternalStorageDirectory();
|
||||
File dataDir = new File(mediaDir, "data");
|
||||
|
||||
if (!mediaDir.exists()) mediaDir.mkdirs();
|
||||
|
||||
Uri uri = data.getData();
|
||||
if (uri == null && data.getClipData() != null) {
|
||||
uri = data.getClipData().getItemAt(0).getUri();
|
||||
}
|
||||
if (uri == null) return;
|
||||
|
||||
File zipFile = new File(mediaDir, "restore.zip");
|
||||
copyUriToFile(uri, zipFile);
|
||||
|
||||
// Cleanup previous data
|
||||
deleteRecursive(dataDir);
|
||||
dataDir.mkdirs();
|
||||
|
||||
unzip(zipFile, mediaDir);
|
||||
|
||||
zipFile.delete();
|
||||
|
||||
mOnSuccess.run();
|
||||
}
|
||||
}
|
||||
|
||||
private void copyUriToFile(Uri uri, File targetDir) {
|
||||
try {
|
||||
String fileName = getFileName(uri);
|
||||
if (fileName == null) fileName = "imported_" + System.currentTimeMillis();
|
||||
|
||||
File outFile = new File(targetDir, fileName);
|
||||
|
||||
InputStream in = mContext.getContentResolver().openInputStream(uri);
|
||||
OutputStream out = new FileOutputStream(outFile);
|
||||
|
||||
byte[] buffer = new byte[8192];
|
||||
int len;
|
||||
while ((len = in.read(buffer)) != -1) {
|
||||
out.write(buffer, 0, len);
|
||||
}
|
||||
|
||||
in.close();
|
||||
out.close();
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private String getFileName(Uri uri) {
|
||||
Cursor cursor = mContext.getContentResolver().query(uri, null, null, null, null);
|
||||
if (cursor != null) {
|
||||
int nameIndex = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
|
||||
cursor.moveToFirst();
|
||||
String name = cursor.getString(nameIndex);
|
||||
cursor.close();
|
||||
return name;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
private File getExternalStorageDirectory() {
|
||||
File result;
|
||||
|
||||
if (VERSION.SDK_INT > 29) {
|
||||
result = mContext.getExternalMediaDirs()[0];
|
||||
|
||||
if (!result.exists()) {
|
||||
result.mkdirs();
|
||||
}
|
||||
} else {
|
||||
result = Environment.getExternalStorageDirectory();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private void zipDirectory(File sourceDir, File zipFile) {
|
||||
try {
|
||||
ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(zipFile));
|
||||
zipFileRecursive(zos, sourceDir, "data/");
|
||||
zos.close();
|
||||
} catch (Exception e) { e.printStackTrace(); }
|
||||
}
|
||||
|
||||
private void zipFileRecursive(ZipOutputStream zos, File file, String base) throws Exception {
|
||||
if (file.isDirectory()) {
|
||||
File[] children = file.listFiles();
|
||||
if (children != null) {
|
||||
for (File child : children) {
|
||||
zipFileRecursive(zos, child, base + child.getName() + "/");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
FileInputStream fis = new FileInputStream(file);
|
||||
zos.putNextEntry(new ZipEntry(base.substring(5, base.length() -1))); // strip "data/" prefix and "/" at the end
|
||||
byte[] buf = new byte[8192];
|
||||
int len;
|
||||
while ((len = fis.read(buf)) > 0) zos.write(buf, 0, len);
|
||||
fis.close();
|
||||
zos.closeEntry();
|
||||
}
|
||||
}
|
||||
|
||||
private void unzip(File zipFile, File targetRoot) {
|
||||
try {
|
||||
ZipInputStream zis = new ZipInputStream(new FileInputStream(zipFile));
|
||||
ZipEntry entry;
|
||||
byte[] buffer = new byte[8192];
|
||||
|
||||
while ((entry = zis.getNextEntry()) != null) {
|
||||
File out = new File(targetRoot, entry.getName());
|
||||
if (entry.isDirectory()) {
|
||||
out.mkdirs();
|
||||
} else {
|
||||
out.getParentFile().mkdirs();
|
||||
FileOutputStream fos = new FileOutputStream(out);
|
||||
int len;
|
||||
while ((len = zis.read(buffer)) > 0) fos.write(buffer, 0, len);
|
||||
fos.close();
|
||||
}
|
||||
zis.closeEntry();
|
||||
}
|
||||
zis.close();
|
||||
} catch (Exception e) { e.printStackTrace(); }
|
||||
}
|
||||
|
||||
private void deleteRecursive(File f) {
|
||||
if (!f.exists()) return;
|
||||
if (f.isDirectory()) {
|
||||
File[] children = f.listFiles();
|
||||
if (children != null) {
|
||||
for (File c : children) deleteRecursive(c);
|
||||
}
|
||||
}
|
||||
f.delete();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,159 @@
|
||||
package com.liskovsoft.smartyoutubetv2.common.misc;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.ClipData;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.os.Build.VERSION;
|
||||
import android.os.Environment;
|
||||
import android.provider.OpenableColumns;
|
||||
|
||||
import androidx.core.content.FileProvider;
|
||||
|
||||
import com.liskovsoft.smartyoutubetv2.common.misc.MotherActivity.OnResult;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class BackupAndRestoreHelperOld implements OnResult {
|
||||
private static final int REQ_PICK_FILES = 1001;
|
||||
private final Context mContext;
|
||||
|
||||
public BackupAndRestoreHelperOld(Context context) {
|
||||
mContext = context;
|
||||
}
|
||||
|
||||
public void exportAppMediaFolder(Context context) {
|
||||
if (VERSION.SDK_INT < 30) {
|
||||
return;
|
||||
}
|
||||
|
||||
File mediaDir = getExternalStorageDirectory();
|
||||
if (mediaDir == null || !mediaDir.exists()) return;
|
||||
|
||||
// TODO: create zip file and send only one file zip
|
||||
File[] files = mediaDir.listFiles();
|
||||
if (files == null || files.length == 0) return;
|
||||
|
||||
ArrayList<Uri> uris = new ArrayList<>();
|
||||
|
||||
for (File file : files) {
|
||||
if (file.isFile()) {
|
||||
Uri uri = FileProvider.getUriForFile(
|
||||
context,
|
||||
context.getPackageName() + ".update_provider",
|
||||
file
|
||||
);
|
||||
uris.add(uri);
|
||||
}
|
||||
}
|
||||
|
||||
if (uris.isEmpty()) return;
|
||||
|
||||
Intent intent = new Intent(Intent.ACTION_SEND_MULTIPLE);
|
||||
intent.setType("*/*");
|
||||
intent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, uris);
|
||||
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
||||
|
||||
context.startActivity(
|
||||
Intent.createChooser(intent, "Send to Total Commander")
|
||||
);
|
||||
}
|
||||
|
||||
public void importAppMediaFolder(Context context) {
|
||||
if (VERSION.SDK_INT < 30) {
|
||||
return;
|
||||
}
|
||||
|
||||
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
|
||||
intent.setType("*/*");
|
||||
intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
|
||||
|
||||
((MotherActivity) mContext).addOnResult(this);
|
||||
|
||||
((Activity) context).startActivityForResult(intent, REQ_PICK_FILES);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResult(int requestCode, int resultCode, Intent data) {
|
||||
if (requestCode == REQ_PICK_FILES && resultCode == Activity.RESULT_OK) {
|
||||
|
||||
if (data == null) return;
|
||||
|
||||
File targetDir = getExternalStorageDirectory();
|
||||
if (!targetDir.exists()) targetDir.mkdirs();
|
||||
|
||||
// Несколько файлов (ClipData)
|
||||
if (data.getClipData() != null) {
|
||||
ClipData clip = data.getClipData();
|
||||
for (int i = 0; i < clip.getItemCount(); i++) {
|
||||
Uri uri = clip.getItemAt(i).getUri();
|
||||
copyUriToFile(mContext, uri, targetDir);
|
||||
}
|
||||
}
|
||||
// Один файл
|
||||
else if (data.getData() != null) {
|
||||
Uri uri = data.getData();
|
||||
copyUriToFile(mContext, uri, targetDir);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void copyUriToFile(Context context, Uri uri, File targetDir) {
|
||||
try {
|
||||
String fileName = getFileName(context, uri);
|
||||
if (fileName == null) fileName = "imported_" + System.currentTimeMillis();
|
||||
|
||||
File outFile = new File(targetDir, fileName);
|
||||
|
||||
InputStream in = context.getContentResolver().openInputStream(uri);
|
||||
OutputStream out = new FileOutputStream(outFile);
|
||||
|
||||
byte[] buffer = new byte[8192];
|
||||
int len;
|
||||
while ((len = in.read(buffer)) != -1) {
|
||||
out.write(buffer, 0, len);
|
||||
}
|
||||
|
||||
in.close();
|
||||
out.close();
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private static String getFileName(Context context, Uri uri) {
|
||||
Cursor cursor = context.getContentResolver().query(uri, null, null, null, null);
|
||||
if (cursor != null) {
|
||||
int nameIndex = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
|
||||
cursor.moveToFirst();
|
||||
String name = cursor.getString(nameIndex);
|
||||
cursor.close();
|
||||
return name;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
private File getExternalStorageDirectory() {
|
||||
File result;
|
||||
|
||||
if (VERSION.SDK_INT > 29) {
|
||||
result = mContext.getExternalMediaDirs()[0];
|
||||
|
||||
if (!result.exists()) {
|
||||
result.mkdirs();
|
||||
}
|
||||
} else {
|
||||
result = Environment.getExternalStorageDirectory();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -26,6 +26,7 @@ public class BackupAndRestoreManager implements MotherActivity.OnPermissions {
|
||||
private static final String SHARED_PREFS_SUBDIR = "shared_prefs";
|
||||
private final List<File> mDataDirs;
|
||||
private final List<File> mBackupDirs;
|
||||
private final BackupAndRestoreHelper mHelper;
|
||||
private Runnable mPendingHandler;
|
||||
|
||||
public interface OnBackupNames {
|
||||
@@ -35,6 +36,8 @@ public class BackupAndRestoreManager implements MotherActivity.OnPermissions {
|
||||
public BackupAndRestoreManager(Context context) {
|
||||
mContext = context;
|
||||
|
||||
mHelper = new BackupAndRestoreHelper(context);
|
||||
|
||||
mDataDirs = new ArrayList<>();
|
||||
mDataDirs.add(new File(mContext.getApplicationInfo().dataDir, SHARED_PREFS_SUBDIR));
|
||||
|
||||
@@ -148,6 +151,8 @@ public class BackupAndRestoreManager implements MotherActivity.OnPermissions {
|
||||
FileHelpers.delete(new File(destination, HiddenPrefs.SHARED_PREFERENCES_NAME + ".xml"));
|
||||
}
|
||||
}
|
||||
|
||||
mHelper.exportAppMediaFolder();
|
||||
}
|
||||
|
||||
private void restoreData(String backupName) {
|
||||
@@ -266,6 +271,10 @@ public class BackupAndRestoreManager implements MotherActivity.OnPermissions {
|
||||
return currentBackup != null ? currentBackup.toString() : null;
|
||||
}
|
||||
|
||||
public String getBackupPathRoot() {
|
||||
return String.format("%s/data", getExternalStorageDirectory());
|
||||
}
|
||||
|
||||
public String getBackupPathCheck() {
|
||||
File currentBackup = getBackupCheck();
|
||||
|
||||
|
||||
@@ -50,8 +50,8 @@ android {
|
||||
applicationId "org.smarttube"
|
||||
minSdkVersion project.properties.minSdkVersion
|
||||
targetSdkVersion project.properties.targetSdkVersion
|
||||
versionCode 2245
|
||||
versionName "30.55"
|
||||
versionCode 2246
|
||||
versionName "30.56"
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
buildConfigField "long", "TIMESTAMP", System.currentTimeMillis() + "L"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user