Merge pull request #44 from grote/cleanup

Cleanup unused code
This commit is contained in:
Steve Soltys 2019-09-25 21:14:57 -04:00 committed by GitHub
commit 8ea68ea6ca
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
48 changed files with 14 additions and 1449 deletions

View file

@ -2,8 +2,8 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.stevesoltys.backup"
android:versionCode="5"
android:versionName="0.3.0">
android:versionCode="6"
android:versionName="1.0.0-alpha1">
<uses-permission
android:name="android.permission.BACKUP"
@ -29,6 +29,7 @@
android:allowBackup="false"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme"
tools:ignore="GoogleAppIndexingWarning">
@ -62,18 +63,6 @@
</intent-filter>
</activity>
<activity
android:name="com.stevesoltys.backup.activity.MainActivity"
android:label="@string/app_name" />
<activity
android:name="com.stevesoltys.backup.activity.backup.CreateBackupActivity"
android:parentActivityName="com.stevesoltys.backup.activity.MainActivity" />
<activity
android:name="com.stevesoltys.backup.activity.restore.RestoreBackupActivity"
android:parentActivityName="com.stevesoltys.backup.activity.MainActivity" />
<service
android:name=".transport.ConfigurableBackupTransportService"
android:exported="false">

View file

@ -1,4 +1,4 @@
package com.stevesoltys.backup.session.backup
package com.stevesoltys.backup
import android.app.backup.BackupManagerMonitor.*
import android.app.backup.IBackupManagerMonitor

View file

@ -1,103 +0,0 @@
package com.stevesoltys.backup.activity;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import com.stevesoltys.backup.R;
import static android.view.View.GONE;
import static android.view.View.VISIBLE;
public class MainActivity extends Activity implements View.OnClickListener {
public static final int OPEN_DOCUMENT_TREE_REQUEST_CODE = 1;
public static final int OPEN_DOCUMENT_TREE_BACKUP_REQUEST_CODE = 2;
public static final int LOAD_DOCUMENT_REQUEST_CODE = 3;
private MainActivityController controller;
private Button automaticBackupsButton;
private Button changeLocationButton;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
controller = new MainActivityController();
findViewById(R.id.create_backup_button).setOnClickListener(this);
findViewById(R.id.restore_backup_button).setOnClickListener(this);
automaticBackupsButton = findViewById(R.id.automatic_backups_button);
automaticBackupsButton.setOnClickListener(this);
changeLocationButton = findViewById(R.id.change_backup_location_button);
changeLocationButton.setOnClickListener(this);
}
@Override
protected void onStart() {
super.onStart();
if (controller.isChangeBackupLocationButtonVisible(this)) {
changeLocationButton.setVisibility(VISIBLE);
} else {
changeLocationButton.setVisibility(GONE);
}
}
@Override
public void onClick(View view) {
int viewId = view.getId();
switch (viewId) {
case R.id.create_backup_button:
controller.onBackupButtonClicked(this);
break;
case R.id.restore_backup_button:
controller.showLoadDocumentActivity(this);
break;
case R.id.automatic_backups_button:
if (controller.onAutomaticBackupsButtonClicked(this)) {
automaticBackupsButton.setVisibility(GONE);
}
break;
case R.id.change_backup_location_button:
controller.onChangeBackupLocationButtonClicked(this);
break;
}
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent result) {
if (resultCode != Activity.RESULT_OK) {
Log.e(MainActivity.class.getName(), "Error in activity result: " + requestCode);
return;
}
switch (requestCode) {
case OPEN_DOCUMENT_TREE_REQUEST_CODE:
controller.handleChooseFolderResult(result, this, false);
break;
case OPEN_DOCUMENT_TREE_BACKUP_REQUEST_CODE:
controller.handleChooseFolderResult(result, this, true);
break;
case LOAD_DOCUMENT_REQUEST_CODE:
controller.handleLoadDocumentResult(result, this);
break;
}
}
}

View file

@ -1,117 +0,0 @@
package com.stevesoltys.backup.activity;
import android.app.Activity;
import android.content.ActivityNotFoundException;
import android.content.Intent;
import android.net.Uri;
import android.widget.Toast;
import com.stevesoltys.backup.activity.backup.CreateBackupActivity;
import com.stevesoltys.backup.activity.restore.RestoreBackupActivity;
import com.stevesoltys.backup.transport.ConfigurableBackupTransportService;
import static android.content.Intent.ACTION_OPEN_DOCUMENT;
import static android.content.Intent.ACTION_OPEN_DOCUMENT_TREE;
import static android.content.Intent.CATEGORY_OPENABLE;
import static android.content.Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION;
import static android.content.Intent.FLAG_GRANT_READ_URI_PERMISSION;
import static android.content.Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
import static com.stevesoltys.backup.activity.MainActivity.OPEN_DOCUMENT_TREE_BACKUP_REQUEST_CODE;
import static com.stevesoltys.backup.activity.MainActivity.OPEN_DOCUMENT_TREE_REQUEST_CODE;
/**
* @author Steve Soltys
* @author Torsten Grote
*/
public class MainActivityController {
public static final String DOCUMENT_MIME_TYPE = "application/octet-stream";
void onBackupButtonClicked(Activity parent) {
Uri folderUri = null;
if (folderUri == null) {
showChooseFolderActivity(parent, true);
} else {
// ensure that backup service is started
parent.startService(new Intent(parent, ConfigurableBackupTransportService.class));
showCreateBackupActivity(parent);
}
}
boolean isChangeBackupLocationButtonVisible(Activity parent) {
return false;
}
private void showChooseFolderActivity(Activity parent, boolean continueToBackup) {
Intent openTreeIntent = new Intent(ACTION_OPEN_DOCUMENT_TREE);
openTreeIntent.addFlags(FLAG_GRANT_PERSISTABLE_URI_PERMISSION |
FLAG_GRANT_READ_URI_PERMISSION | FLAG_GRANT_WRITE_URI_PERMISSION);
try {
Intent documentChooser = Intent.createChooser(openTreeIntent, "Select the backup location");
int requestCode = continueToBackup ? OPEN_DOCUMENT_TREE_BACKUP_REQUEST_CODE : OPEN_DOCUMENT_TREE_REQUEST_CODE;
parent.startActivityForResult(documentChooser, requestCode);
} catch (ActivityNotFoundException ex) {
Toast.makeText(parent, "Please install a file manager.", Toast.LENGTH_SHORT).show();
}
}
void showLoadDocumentActivity(Activity parent) {
Intent loadDocumentIntent = new Intent(ACTION_OPEN_DOCUMENT);
loadDocumentIntent.addCategory(CATEGORY_OPENABLE);
loadDocumentIntent.setType(DOCUMENT_MIME_TYPE);
try {
Intent documentChooser = Intent.createChooser(loadDocumentIntent, "Select the backup location");
parent.startActivityForResult(documentChooser, MainActivity.LOAD_DOCUMENT_REQUEST_CODE);
} catch (ActivityNotFoundException ex) {
Toast.makeText(parent, "Please install a file manager.", Toast.LENGTH_SHORT).show();
}
}
boolean onAutomaticBackupsButtonClicked(Activity parent) {
Toast.makeText(parent, "Please make at least one manual backup first.", Toast.LENGTH_SHORT).show();
return false;
}
void onChangeBackupLocationButtonClicked(Activity parent) {
showChooseFolderActivity(parent, false);
}
void handleChooseFolderResult(Intent result, Activity parent, boolean continueToBackup) {
if (result == null || result.getData() == null) {
return;
}
Uri folderUri = result.getData();
// persist permission to access backup folder across reboots
int takeFlags = result.getFlags() &
(FLAG_GRANT_READ_URI_PERMISSION | FLAG_GRANT_WRITE_URI_PERMISSION);
parent.getContentResolver().takePersistableUriPermission(folderUri, takeFlags);
if (!continueToBackup) return;
showCreateBackupActivity(parent);
}
private void showCreateBackupActivity(Activity parent) {
Intent intent = new Intent(parent, CreateBackupActivity.class);
parent.startActivity(intent);
}
void handleLoadDocumentResult(Intent result, Activity parent) {
if (result == null) {
return;
}
Intent intent = new Intent(parent, RestoreBackupActivity.class);
intent.setData(result.getData());
parent.startActivity(intent);
}
}

View file

@ -1,60 +0,0 @@
package com.stevesoltys.backup.activity;
import android.app.Activity;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListView;
import com.stevesoltys.backup.R;
import java.util.HashSet;
import java.util.Set;
import java.util.stream.IntStream;
/**
* @author Steve Soltys
*/
public abstract class PackageListActivity extends Activity implements AdapterView.OnItemClickListener {
protected ListView packageListView;
protected final Set<String> selectedPackageList = new HashSet<>();
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
String clickedPackage = (String) packageListView.getItemAtPosition(position);
if (!selectedPackageList.remove(clickedPackage)) {
selectedPackageList.add(clickedPackage);
packageListView.setItemChecked(position, true);
} else {
packageListView.setItemChecked(position, false);
}
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == R.id.action_unselect_all) {
IntStream.range(0, packageListView.getCount())
.forEach(position -> {
selectedPackageList.remove((String) packageListView.getItemAtPosition(position));
packageListView.setItemChecked(position, false);
});
return true;
}
return super.onOptionsItemSelected(item);
}
public void preSelectAllPackages() {
IntStream.range(0, packageListView.getCount())
.forEach(position -> {
selectedPackageList.add((String) packageListView.getItemAtPosition(position));
packageListView.setItemChecked(position, true);
});
}
}

View file

@ -1,32 +0,0 @@
package com.stevesoltys.backup.activity;
import android.app.Activity;
import android.content.Context;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.PopupWindow;
import com.stevesoltys.backup.R;
/**
* @author Steve Soltys
*/
public class PopupWindowUtil {
public static PopupWindow showLoadingPopupWindow(Activity parent) {
LayoutInflater inflater = (LayoutInflater) parent.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
ViewGroup popupViewGroup = parent.findViewById(R.id.popup_layout);
View popupView = inflater.inflate(R.layout.progress_popup_window, popupViewGroup);
PopupWindow popupWindow = new PopupWindow(popupView, 750, 350, true);
popupWindow.setBackgroundDrawable(new ColorDrawable(Color.WHITE));
popupWindow.setElevation(10);
popupWindow.setFocusable(false);
popupWindow.showAtLocation(popupView, Gravity.CENTER, 0, 0);
popupWindow.setOutsideTouchable(false);
return popupWindow;
}
}

View file

@ -1,37 +0,0 @@
package com.stevesoltys.backup.activity.backup;
import android.os.RemoteException;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import com.stevesoltys.backup.R;
import com.stevesoltys.backup.session.backup.BackupResult;
import com.stevesoltys.backup.session.backup.BackupSession;
/**
* @author Steve Soltys
*/
public class BackupPopupWindowListener implements Button.OnClickListener {
private static final String TAG = BackupPopupWindowListener.class.getName();
private final BackupSession backupSession;
public BackupPopupWindowListener(BackupSession backupSession) {
this.backupSession = backupSession;
}
@Override
public void onClick(View view) {
int viewId = view.getId();
if (viewId == R.id.popup_cancel_button) {
try {
backupSession.stop(BackupResult.CANCELLED);
} catch (RemoteException e) {
Log.e(TAG, "Error cancelling backup session: ", e);
}
}
}
}

View file

@ -1,45 +0,0 @@
package com.stevesoltys.backup.activity.backup;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.View;
import com.stevesoltys.backup.R;
import com.stevesoltys.backup.activity.PackageListActivity;
public class CreateBackupActivity extends PackageListActivity implements View.OnClickListener {
private CreateBackupActivityController controller;
@Override
public void onClick(View view) {
int viewId = view.getId();
if (viewId == R.id.create_confirm_button) {
controller.onCreateBackupButtonClicked(selectedPackageList, this);
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_create_backup);
findViewById(R.id.create_confirm_button).setOnClickListener(this);
packageListView = findViewById(R.id.create_package_list);
selectedPackageList.clear();
controller = new CreateBackupActivityController();
AsyncTask.execute(() -> controller.populatePackageList(packageListView, CreateBackupActivity.this));
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.backup_menu, menu);
return true;
}
}

View file

@ -1,126 +0,0 @@
package com.stevesoltys.backup.activity.backup;
import android.app.Activity;
import android.app.AlertDialog;
import android.os.RemoteException;
import android.text.InputType;
import android.util.Log;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.PopupWindow;
import android.widget.TextView;
import android.widget.Toast;
import com.stevesoltys.backup.R;
import com.stevesoltys.backup.activity.PopupWindowUtil;
import com.stevesoltys.backup.service.PackageService;
import com.stevesoltys.backup.service.backup.BackupService;
import java.util.Set;
import java.util.concurrent.atomic.AtomicReference;
/**
* @author Steve Soltys
*/
class CreateBackupActivityController {
private static final String TAG = CreateBackupActivityController.class.getName();
private final BackupService backupService = new BackupService();
private final PackageService packageService = new PackageService();
void populatePackageList(ListView packageListView, CreateBackupActivity parent) {
AtomicReference<PopupWindow> popupWindow = new AtomicReference<>();
parent.runOnUiThread(() -> {
popupWindow.set(PopupWindowUtil.showLoadingPopupWindow(parent));
TextView textView = popupWindow.get().getContentView().findViewById(R.id.popup_text_view);
textView.setText(R.string.loading_packages);
View popupWindowButton = popupWindow.get().getContentView().findViewById(R.id.popup_cancel_button);
popupWindowButton.setOnClickListener(view -> parent.finish());
});
String[] eligiblePackageList;
try {
eligiblePackageList = packageService.getEligiblePackages();
} catch (RemoteException e) {
Log.e(TAG, "Error while obtaining package list: ", e);
Toast.makeText(parent, "Error obtaining package list", Toast.LENGTH_SHORT).show();
parent.finish();
return;
}
parent.runOnUiThread(() -> {
if (popupWindow.get() != null) {
popupWindow.get().dismiss();
}
packageListView.setOnItemClickListener(parent);
packageListView.setAdapter(new ArrayAdapter<>(parent, R.layout.checked_list_item, eligiblePackageList));
packageListView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
parent.preSelectAllPackages();
});
}
void onCreateBackupButtonClicked(Set<String> selectedPackages, Activity parent) {
backupService.backupPackageData(selectedPackages, parent);
}
private void showEnterPasswordAlert(Set<String> selectedPackages, Activity parent) {
final EditText passwordTextView = new EditText(parent);
passwordTextView.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD);
new AlertDialog.Builder(parent)
.setTitle("Enter a password")
.setMessage("You'll need this to restore your backup, so write it down!")
.setView(passwordTextView)
.setPositiveButton("Set password", (dialog, button) -> {
if (passwordTextView.getText().length() == 0) {
Toast.makeText(parent, "Please enter a password", Toast.LENGTH_SHORT).show();
dialog.cancel();
showEnterPasswordAlert(selectedPackages, parent);
} else {
showConfirmPasswordAlert(selectedPackages, parent,
passwordTextView.getText().toString());
}
})
.setNegativeButton("Cancel", (dialog, button) -> dialog.cancel())
.show();
}
private void showConfirmPasswordAlert(Set<String> selectedPackages, Activity parent,
String originalPassword) {
final EditText passwordTextView = new EditText(parent);
passwordTextView.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD);
new AlertDialog.Builder(parent)
.setTitle("Confirm password")
.setView(passwordTextView)
.setPositiveButton("Confirm", (dialog, button) -> {
String password = passwordTextView.getText().toString();
if (originalPassword.equals(password)) {
backupService.backupPackageData(selectedPackages, parent);
} else {
new AlertDialog.Builder(parent)
.setMessage("Passwords do not match, please try again.")
.setPositiveButton("Ok", (dialog2, button2) -> dialog2.dismiss())
.show();
dialog.cancel();
}
})
.setNegativeButton("Cancel", (dialog, button) -> dialog.cancel())
.show();
}
}

View file

@ -1,50 +0,0 @@
package com.stevesoltys.backup.activity.restore;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.View;
import com.stevesoltys.backup.R;
import com.stevesoltys.backup.activity.PackageListActivity;
public class RestoreBackupActivity extends PackageListActivity implements View.OnClickListener {
private RestoreBackupActivityController controller;
private Uri contentUri;
@Override
public void onClick(View view) {
int viewId = view.getId();
if (viewId == R.id.restore_confirm_button) {
controller.showEnterPasswordAlert(selectedPackageList, contentUri, this);
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_restore_backup);
findViewById(R.id.restore_confirm_button).setOnClickListener(this);
packageListView = findViewById(R.id.restore_package_list);
selectedPackageList.clear();
contentUri = getIntent().getData();
controller = new RestoreBackupActivityController();
AsyncTask.execute(() -> controller.populatePackageList(packageListView, contentUri, this));
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.backup_menu, menu);
return true;
}
}

View file

@ -1,117 +0,0 @@
package com.stevesoltys.backup.activity.restore;
import android.app.Activity;
import android.app.AlertDialog;
import android.net.Uri;
import android.os.ParcelFileDescriptor;
import android.text.InputType;
import android.util.Log;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.PopupWindow;
import android.widget.TextView;
import com.stevesoltys.backup.R;
import com.stevesoltys.backup.activity.PopupWindowUtil;
import com.stevesoltys.backup.service.restore.RestoreService;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.atomic.AtomicReference;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import libcore.io.IoUtils;
import static com.stevesoltys.backup.transport.backup.plugins.DocumentsStorageKt.DIRECTORY_FULL_BACKUP;
/**
* @author Steve Soltys
*/
class RestoreBackupActivityController {
private static final String TAG = RestoreBackupActivityController.class.getName();
private final RestoreService restoreService = new RestoreService();
void populatePackageList(ListView packageListView, Uri contentUri, RestoreBackupActivity parent) {
AtomicReference<PopupWindow> popupWindow = new AtomicReference<>();
parent.runOnUiThread(() -> {
popupWindow.set(PopupWindowUtil.showLoadingPopupWindow(parent));
TextView textView = popupWindow.get().getContentView().findViewById(R.id.popup_text_view);
textView.setText(R.string.loading_backup);
View popupWindowButton = popupWindow.get().getContentView().findViewById(R.id.popup_cancel_button);
popupWindowButton.setOnClickListener(view -> parent.finish());
});
List<String> eligiblePackageList = new LinkedList<>();
try {
eligiblePackageList.addAll(getEligiblePackages(contentUri, parent));
} catch (IOException e) {
Log.e(TAG, "Error while obtaining package list: ", e);
}
parent.runOnUiThread(() -> {
if (popupWindow.get() != null) {
popupWindow.get().dismiss();
}
packageListView.setOnItemClickListener(parent);
packageListView.setAdapter(new ArrayAdapter<>(parent, R.layout.checked_list_item, eligiblePackageList));
packageListView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
parent.preSelectAllPackages();
});
}
private List<String> getEligiblePackages(Uri contentUri, Activity context) throws IOException {
List<String> results = new LinkedList<>();
ParcelFileDescriptor fileDescriptor = context.getContentResolver().openFileDescriptor(contentUri, "r");
FileInputStream fileInputStream = new FileInputStream(fileDescriptor.getFileDescriptor());
ZipInputStream inputStream = new ZipInputStream(fileInputStream);
ZipEntry zipEntry;
while ((zipEntry = inputStream.getNextEntry()) != null) {
String zipEntryPath = zipEntry.getName();
if (zipEntryPath.startsWith(DIRECTORY_FULL_BACKUP)) {
String fileName = new File(zipEntryPath).getName();
results.add(fileName);
}
inputStream.closeEntry();
}
IoUtils.closeQuietly(inputStream);
IoUtils.closeQuietly(fileDescriptor.getFileDescriptor());
return results;
}
void showEnterPasswordAlert(Set<String> selectedPackages, Uri contentUri, Activity parent) {
final EditText passwordTextView = new EditText(parent);
passwordTextView.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD);
new AlertDialog.Builder(parent)
.setTitle("Enter a password")
.setMessage("If you didn't enter one while creating the backup, you can leave this blank.")
.setView(passwordTextView)
.setPositiveButton("Confirm", (dialog, button) ->
restoreService.restorePackages(selectedPackages, contentUri, parent,
passwordTextView.getText().toString()))
.setNegativeButton("Cancel", (dialog, button) -> dialog.cancel())
.show();
}
}

View file

@ -1,41 +0,0 @@
package com.stevesoltys.backup.activity.restore;
import android.os.RemoteException;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import com.stevesoltys.backup.R;
import com.stevesoltys.backup.session.restore.RestoreResult;
import com.stevesoltys.backup.session.restore.RestoreSession;
/**
* @author Steve Soltys
*/
public class RestorePopupWindowListener implements Button.OnClickListener {
private static final String TAG = RestorePopupWindowListener.class.getName();
private final RestoreSession restoreSession;
public RestorePopupWindowListener(RestoreSession restoreSession) {
this.restoreSession = restoreSession;
}
@Override
public void onClick(View view) {
int viewId = view.getId();
switch (viewId) {
case R.id.popup_cancel_button:
try {
restoreSession.stop(RestoreResult.CANCELLED);
} catch (RemoteException e) {
Log.e(TAG, "Error cancelling restore session: ", e);
}
break;
}
}
}

View file

@ -1,5 +1,6 @@
package com.stevesoltys.backup.restore
import android.app.Activity.RESULT_OK
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
@ -64,7 +65,10 @@ class RestoreProgressFragment : Fragment() {
activity?.window?.clearFlags(FLAG_KEEP_SCREEN_ON)
})
button.setOnClickListener { requireActivity().finishAfterTransition() }
button.setOnClickListener {
requireActivity().setResult(RESULT_OK)
requireActivity().finishAfterTransition()
}
}
}

View file

@ -11,7 +11,7 @@ import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import com.stevesoltys.backup.Backup
import com.stevesoltys.backup.R
import com.stevesoltys.backup.session.backup.BackupMonitor
import com.stevesoltys.backup.BackupMonitor
import com.stevesoltys.backup.transport.TRANSPORT_ID
import com.stevesoltys.backup.ui.RequireProvisioningViewModel

View file

@ -1,56 +0,0 @@
package com.stevesoltys.backup.service;
import android.app.backup.IBackupManager;
import android.os.RemoteException;
import android.os.ServiceManager;
import com.stevesoltys.backup.session.backup.BackupSession;
import com.stevesoltys.backup.session.backup.BackupSessionObserver;
import com.stevesoltys.backup.session.restore.RestoreSession;
import com.stevesoltys.backup.session.restore.RestoreSessionObserver;
import java.util.Set;
/**
* @author Steve Soltys
*/
public class TransportService {
private static final String BACKUP_TRANSPORT = "com.stevesoltys.backup.transport.ConfigurableBackupTransport";
private final IBackupManager backupManager;
public TransportService() {
backupManager = IBackupManager.Stub.asInterface(ServiceManager.getService("backup"));
}
public BackupSession backup(BackupSessionObserver observer, Set<String> packages) throws RemoteException {
if (!BACKUP_TRANSPORT.equals(backupManager.getCurrentTransport())) {
backupManager.selectBackupTransport(BACKUP_TRANSPORT);
}
if (!backupManager.isBackupEnabled()) {
backupManager.setBackupEnabled(true);
}
BackupSession backupSession = new BackupSession(backupManager, observer, packages);
backupSession.start();
return backupSession;
}
public RestoreSession restore(RestoreSessionObserver observer, Set<String> packages) throws RemoteException {
if (!BACKUP_TRANSPORT.equals(backupManager.getCurrentTransport())) {
backupManager.selectBackupTransport(BACKUP_TRANSPORT);
}
if (!backupManager.isBackupEnabled()) {
backupManager.setBackupEnabled(true);
}
RestoreSession restoreSession = new RestoreSession(backupManager, observer, packages);
restoreSession.start();
return restoreSession;
}
}

View file

@ -1,77 +0,0 @@
package com.stevesoltys.backup.service.backup;
import android.app.Activity;
import android.app.backup.BackupProgress;
import android.widget.PopupWindow;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
import com.stevesoltys.backup.R;
import com.stevesoltys.backup.session.backup.BackupResult;
import com.stevesoltys.backup.session.backup.BackupSession;
import com.stevesoltys.backup.session.backup.BackupSessionObserver;
/**
* @author Steve Soltys
*/
class BackupObserver implements BackupSessionObserver {
private final Activity context;
private final PopupWindow popupWindow;
BackupObserver(Activity context, PopupWindow popupWindow) {
this.context = context;
this.popupWindow = popupWindow;
}
@Override
public void backupPackageStarted(BackupSession backupSession, String packageName, BackupProgress backupProgress) {
context.runOnUiThread(() -> {
TextView textView = popupWindow.getContentView().findViewById(R.id.popup_text_view);
if (textView != null) {
textView.setText(packageName);
}
ProgressBar progressBar = popupWindow.getContentView().findViewById(R.id.popup_progress_bar);
if (progressBar != null) {
progressBar.setMax((int) backupProgress.bytesExpected);
progressBar.setProgress((int) backupProgress.bytesTransferred);
}
});
}
@Override
public void backupPackageCompleted(BackupSession backupSession, String packageName, BackupResult result) {
context.runOnUiThread(() -> {
TextView textView = popupWindow.getContentView().findViewById(R.id.popup_text_view);
if (textView != null) {
textView.setText(packageName);
}
});
}
@Override
public void backupSessionCompleted(BackupSession backupSession, BackupResult backupResult) {
context.runOnUiThread(() -> {
if (backupResult == BackupResult.SUCCESS) {
Toast.makeText(context, R.string.backup_success, Toast.LENGTH_LONG).show();
} else if (backupResult == BackupResult.CANCELLED) {
Toast.makeText(context, R.string.backup_cancelled, Toast.LENGTH_LONG).show();
} else {
Toast.makeText(context, R.string.backup_failure, Toast.LENGTH_LONG).show();
}
popupWindow.dismiss();
context.finish();
});
}
}

View file

@ -1,46 +0,0 @@
package com.stevesoltys.backup.service.backup;
import android.app.Activity;
import android.util.Log;
import android.view.View;
import android.widget.PopupWindow;
import android.widget.TextView;
import com.stevesoltys.backup.R;
import com.stevesoltys.backup.activity.PopupWindowUtil;
import com.stevesoltys.backup.activity.backup.BackupPopupWindowListener;
import com.stevesoltys.backup.service.TransportService;
import com.stevesoltys.backup.session.backup.BackupSession;
import java.util.Set;
/**
* @author Steve Soltys
*/
public class BackupService {
private static final String TAG = BackupService.class.getName();
private final TransportService transportService = new TransportService();
public void backupPackageData(Set<String> selectedPackages, Activity parent) {
try {
selectedPackages.add("@pm@");
Log.i(TAG, "Backing up " + selectedPackages.size() + " packages...");
PopupWindow popupWindow = PopupWindowUtil.showLoadingPopupWindow(parent);
BackupObserver backupObserver = new BackupObserver(parent, popupWindow);
BackupSession backupSession = transportService.backup(backupObserver, selectedPackages);
View popupWindowButton = popupWindow.getContentView().findViewById(R.id.popup_cancel_button);
popupWindowButton.setOnClickListener(new BackupPopupWindowListener(backupSession));
TextView textView = popupWindow.getContentView().findViewById(R.id.popup_text_view);
textView.setText(R.string.initializing);
} catch (Exception e) {
Log.e(TAG, "Error while running backup: ", e);
}
}
}

View file

@ -1,73 +0,0 @@
package com.stevesoltys.backup.service.restore;
import android.app.Activity;
import android.widget.PopupWindow;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
import com.stevesoltys.backup.R;
import com.stevesoltys.backup.session.restore.RestoreResult;
import com.stevesoltys.backup.session.restore.RestoreSessionObserver;
/**
* @author Steve Soltys
*/
class RestoreObserver implements RestoreSessionObserver {
private final Activity context;
private final PopupWindow popupWindow;
private final int packageCount;
RestoreObserver(Activity context, PopupWindow popupWindow, int packageCount) {
this.context = context;
this.popupWindow = popupWindow;
this.packageCount = packageCount;
}
@Override
public void restoreSessionStarted(int packageCount) {
context.runOnUiThread(() -> {
TextView textView = popupWindow.getContentView().findViewById(R.id.popup_text_view);
textView.setText(R.string.initializing);
});
}
@Override
public void restorePackageStarted(int packageIndex, String packageName) {
context.runOnUiThread(() -> {
ProgressBar progressBar = popupWindow.getContentView().findViewById(R.id.popup_progress_bar);
if (progressBar != null) {
progressBar.setMax(packageCount);
progressBar.setProgress(packageIndex);
}
TextView textView = popupWindow.getContentView().findViewById(R.id.popup_text_view);
if (textView != null) {
textView.setText(packageName);
}
});
}
@Override
public void restoreSessionCompleted(RestoreResult restoreResult) {
context.runOnUiThread(() -> {
if (restoreResult == RestoreResult.SUCCESS) {
Toast.makeText(context, R.string.restore_success, Toast.LENGTH_LONG).show();
} else if (restoreResult == RestoreResult.CANCELLED) {
Toast.makeText(context, R.string.restore_cancelled, Toast.LENGTH_LONG).show();
} else {
Toast.makeText(context, R.string.restore_failure, Toast.LENGTH_LONG).show();
}
popupWindow.dismiss();
context.finish();
});
}
}

View file

@ -1,43 +0,0 @@
package com.stevesoltys.backup.service.restore;
import android.app.Activity;
import android.net.Uri;
import android.os.RemoteException;
import android.util.Log;
import android.view.View;
import android.widget.PopupWindow;
import com.stevesoltys.backup.R;
import com.stevesoltys.backup.activity.PopupWindowUtil;
import com.stevesoltys.backup.activity.restore.RestorePopupWindowListener;
import com.stevesoltys.backup.service.TransportService;
import com.stevesoltys.backup.session.restore.RestoreSession;
import java.util.Set;
/**
* @author Steve Soltys
*/
public class RestoreService {
private static final String TAG = RestoreService.class.getName();
private final TransportService transportService = new TransportService();
public void restorePackages(Set<String> selectedPackages, Uri contentUri, Activity parent, String password) {
try {
PopupWindow popupWindow = PopupWindowUtil.showLoadingPopupWindow(parent);
RestoreObserver restoreObserver = new RestoreObserver(parent, popupWindow, selectedPackages.size());
RestoreSession restoreSession = transportService.restore(restoreObserver, selectedPackages);
View popupWindowButton = popupWindow.getContentView().findViewById(R.id.popup_cancel_button);
if (popupWindowButton != null) {
popupWindowButton.setOnClickListener(new RestorePopupWindowListener(restoreSession));
}
} catch (RemoteException e) {
Log.e(TAG, "Error while running restore: ", e);
}
}
}

View file

@ -1,8 +0,0 @@
package com.stevesoltys.backup.session.backup;
/**
* @author Steve Soltys
*/
public enum BackupResult {
SUCCESS, FAILURE, CANCELLED
}

View file

@ -1,67 +0,0 @@
package com.stevesoltys.backup.session.backup;
import android.app.backup.BackupManager;
import android.app.backup.BackupProgress;
import android.app.backup.IBackupManager;
import android.app.backup.IBackupObserver;
import android.os.RemoteException;
import java.util.Set;
import static android.app.backup.BackupManager.FLAG_NON_INCREMENTAL_BACKUP;
/**
* @author Steve Soltys
*/
public class BackupSession extends IBackupObserver.Stub {
private final IBackupManager backupManager;
private final BackupSessionObserver backupSessionObserver;
private final Set<String> packages;
public BackupSession(IBackupManager backupManager, BackupSessionObserver backupSessionObserver,
Set<String> packages) {
this.backupManager = backupManager;
this.backupSessionObserver = backupSessionObserver;
this.packages = packages;
}
public void start() throws RemoteException {
String [] selectedPackageArray = packages.toArray(new String[0]);
backupManager.requestBackup(selectedPackageArray, this, new BackupMonitor(), FLAG_NON_INCREMENTAL_BACKUP);
}
public void stop(BackupResult result) throws RemoteException {
backupManager.cancelBackups();
backupSessionObserver.backupSessionCompleted(this, result);
}
@Override
public void onUpdate(String currentPackage, BackupProgress backupProgress) {
backupSessionObserver.backupPackageStarted(this, currentPackage, backupProgress);
}
@Override
public void onResult(String currentPackage, int status) {
backupSessionObserver.backupPackageCompleted(this, currentPackage, getBackupResult(status));
}
@Override
public void backupFinished(int status) {
backupSessionObserver.backupSessionCompleted(this, getBackupResult(status));
}
private BackupResult getBackupResult(int status) {
if (status == BackupManager.SUCCESS) {
return BackupResult.SUCCESS;
} else if (status == BackupManager.ERROR_BACKUP_CANCELLED) {
return BackupResult.CANCELLED;
} else {
return BackupResult.FAILURE;
}
}
}

View file

@ -1,15 +0,0 @@
package com.stevesoltys.backup.session.backup;
import android.app.backup.BackupProgress;
/**
* @author Steve Soltys
*/
public interface BackupSessionObserver {
void backupPackageStarted(BackupSession backupSession, String packageName, BackupProgress backupProgress);
void backupPackageCompleted(BackupSession backupSession, String packageName, BackupResult result);
void backupSessionCompleted(BackupSession backupSession, BackupResult result);
}

View file

@ -1,8 +0,0 @@
package com.stevesoltys.backup.session.restore;
/**
* @author Steve Soltys
*/
public enum RestoreResult {
SUCCESS, CANCELLED, FAILURE
}

View file

@ -1,100 +0,0 @@
package com.stevesoltys.backup.session.restore;
import android.app.backup.BackupManager;
import android.app.backup.IBackupManager;
import android.app.backup.IRestoreObserver;
import android.app.backup.IRestoreSession;
import android.app.backup.RestoreSet;
import android.os.RemoteException;
import android.os.UserHandle;
import java.util.Set;
/**
* @author Steve Soltys
*/
public class RestoreSession extends IRestoreObserver.Stub {
private final IBackupManager backupManager;
private final RestoreSessionObserver observer;
private final Set<String> packages;
private IRestoreSession restoreSession;
public RestoreSession(IBackupManager backupManager, RestoreSessionObserver observer, Set<String> packages) {
this.backupManager = backupManager;
this.observer = observer;
this.packages = packages;
}
public void start() throws RemoteException {
if (restoreSession != null || packages.isEmpty()) {
observer.restoreSessionCompleted(RestoreResult.FAILURE);
return;
}
restoreSession = backupManager.beginRestoreSessionForUser(UserHandle.myUserId(), null, null);
if (restoreSession == null) {
stop(RestoreResult.FAILURE);
return;
}
int result = restoreSession.getAvailableRestoreSets(this, null);
if (result != BackupManager.SUCCESS) {
stop(RestoreResult.FAILURE);
}
}
public void stop(RestoreResult restoreResult) throws RemoteException {
clearSession();
observer.restoreSessionCompleted(restoreResult);
}
private void clearSession() throws RemoteException {
if (restoreSession != null) {
restoreSession.endRestoreSession();
restoreSession = null;
}
}
@Override
public void restoreSetsAvailable(RestoreSet[] restoreSets) throws RemoteException {
if (restoreSets.length > 0) {
RestoreSet restoreSet = restoreSets[0];
String[] packageArray = packages.toArray(new String[0]);
int result = restoreSession.restorePackages(restoreSet.token, this, packageArray, null);
if (result != BackupManager.SUCCESS) {
stop(RestoreResult.FAILURE);
}
}
}
@Override
public void restoreStarting(int numPackages) {
observer.restoreSessionStarted(numPackages);
}
@Override
public void onUpdate(int nowBeingRestored, String currentPackage) {
observer.restorePackageStarted(nowBeingRestored, currentPackage);
}
@Override
public void restoreFinished(int result) throws RemoteException {
if (result == BackupManager.SUCCESS) {
stop(RestoreResult.SUCCESS);
} else if (result == BackupManager.ERROR_BACKUP_CANCELLED) {
stop(RestoreResult.CANCELLED);
} else {
stop(RestoreResult.FAILURE);
}
}
}

View file

@ -1,13 +0,0 @@
package com.stevesoltys.backup.session.restore;
/**
* @author Steve Soltys
*/
public interface RestoreSessionObserver {
void restoreSessionStarted(int packageCount);
void restorePackageStarted(int packageIndex, String packageName);
void restoreSessionCompleted(RestoreResult restoreResult);
}

View file

@ -2,7 +2,6 @@ package com.stevesoltys.backup.transport
import android.app.Service
import android.app.backup.BackupManager
import android.app.backup.BackupTransport
import android.content.Context
import android.content.Context.BACKUP_SERVICE
import android.app.backup.BackupManager.FLAG_NON_INCREMENTAL_BACKUP
@ -15,8 +14,7 @@ import androidx.annotation.WorkerThread
import com.stevesoltys.backup.Backup
import com.stevesoltys.backup.NotificationBackupObserver
import com.stevesoltys.backup.R
import com.stevesoltys.backup.service.PackageService
import com.stevesoltys.backup.session.backup.BackupMonitor
import com.stevesoltys.backup.BackupMonitor
private val TAG = ConfigurableBackupTransportService::class.java.simpleName

View file

@ -1,4 +1,4 @@
package com.stevesoltys.backup.service
package com.stevesoltys.backup.transport
import android.content.pm.IPackageManager
import android.content.pm.PackageInfo
@ -27,7 +27,7 @@ private val IGNORED_PACKAGES = newArraySet(
* @author Steve Soltys
* @author Torsten Grote
*/
class PackageService {
internal class PackageService {
private val backupManager = Backup.backupManager
private val packageManager: IPackageManager = IPackageManager.Stub.asInterface(getService("package"))

View file

@ -1,26 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_create_backup"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:weightSum="1"
tools:context="com.stevesoltys.backup.activity.restore.RestoreBackupActivity">
<ListView
android:id="@+id/create_package_list"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="0.99" />
<Button
android:id="@+id/create_confirm_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/button_vertical_margin"
android:layout_marginLeft="@dimen/button_horizontal_margin"
android:layout_marginRight="@dimen/button_horizontal_margin"
android:text="@string/create_backup_button" />
</LinearLayout>

View file

@ -1,46 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.stevesoltys.backup.activity.MainActivity">
<Button
android:id="@+id/create_backup_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/button_horizontal_margin"
android:layout_marginTop="@dimen/button_vertical_margin"
android:layout_marginRight="@dimen/button_horizontal_margin"
android:text="@string/create_backup_button" />
<Button
android:id="@+id/restore_backup_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/button_horizontal_margin"
android:layout_marginTop="@dimen/button_vertical_margin"
android:layout_marginRight="@dimen/button_horizontal_margin"
android:text="@string/restore_backup_button" />
<Button
android:id="@+id/automatic_backups_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="48dp"
android:layout_marginLeft="@dimen/button_horizontal_margin"
android:layout_marginRight="@dimen/button_horizontal_margin"
android:text="Activate automatic backups" />
<Button
android:id="@+id/change_backup_location_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/button_horizontal_margin"
android:layout_marginTop="72dp"
android:layout_marginRight="@dimen/button_horizontal_margin"
android:text="@string/change_backup_location_button" />
</LinearLayout>

View file

@ -1,26 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_restore_backup"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:weightSum="1"
tools:context="com.stevesoltys.backup.activity.restore.RestoreBackupActivity">
<ListView
android:id="@+id/restore_package_list"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="0.99"/>
<Button
android:id="@+id/restore_confirm_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/button_horizontal_margin"
android:layout_marginRight="@dimen/button_horizontal_margin"
android:layout_marginTop="@dimen/button_vertical_margin"
android:text="@string/restore_button"/>
</LinearLayout>

View file

@ -1,10 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<CheckedTextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@android:id/text1"
android:layout_width="match_parent"
android:layout_height="?android:attr/listPreferredItemHeightSmall"
android:textAppearance="?android:attr/textAppearanceListItemSmall"
android:gravity="center_vertical"
android:checkMark="?android:attr/listChoiceIndicatorMultiple"
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd" />

View file

@ -1,30 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/popup_layout"
android:layout_width="@dimen/popup_width"
android:layout_height="@dimen/popup_height"
android:orientation="vertical">
<TextView
android:id="@+id/popup_text_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAlignment="center" />
<ProgressBar
android:id="@+id/popup_progress_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/progress_bar_horizontal_margin"
android:layout_marginRight="@dimen/progress_bar_horizontal_margin" />
<Button
android:id="@+id/popup_cancel_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/button_horizontal_margin"
android:layout_marginTop="@dimen/button_vertical_margin"
android:layout_marginRight="@dimen/button_horizontal_margin"
android:text="@string/popup_cancel" />
</LinearLayout>

View file

@ -1,8 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+id/action_unselect_all"
android:title="@string/unselect_all"
android:showAsAction="never" />
</menu>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

View file

@ -1,6 +0,0 @@
<resources>
<!-- Example customization of dimensions originally defined in res/values/dimens.xml
(such as screen margins) for screens with more than 820dp of available width. This
would include 7" and 10" devices in landscape (~960dp and ~1280dp respectively). -->
<dimen name="activity_horizontal_margin">64dp</dimen>
</resources>

View file

@ -1,8 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorPrimary">#3F51B5</color>
<color name="colorPrimaryDark">#303F9F</color>
<color name="colorAccent">#FF4081</color>
<color name="divider">#8A000000</color>
</resources>

View file

@ -1,13 +0,0 @@
<resources>
<!-- Default screen margins, per the Android Design guidelines. -->
<dimen name="activity_horizontal_margin">16dp</dimen>
<dimen name="activity_vertical_margin">16dp</dimen>
<dimen name="button_horizontal_margin">5dp</dimen>
<dimen name="button_vertical_margin">7dp</dimen>
<dimen name="progress_bar_horizontal_margin">5dp</dimen>
<dimen name="popup_width">300dp</dimen>
<dimen name="popup_height">300dp</dimen>
</resources>

View file

@ -1,27 +1,8 @@
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name">Backup</string>
<string name="create_backup_button">Create backup</string>
<string name="restore_backup_button">Restore backup</string>
<string name="change_backup_location_button">Change backup location</string>
<string name="backup_success">Backup success</string>
<string name="backup_failure">Backup failure</string>
<string name="backup_cancelled">Backup cancelled</string>
<string name="backup_in_progress">Backup already in progress</string>
<string name="restore_button">Restore packages</string>
<string name="restore_success">Restore success</string>
<string name="restore_failure">Restore failure</string>
<string name="restore_cancelled">Restore cancelled</string>
<string name="restore_in_progress">Restore already in progress</string>
<string name="popup_cancel">Cancel</string>
<string name="unselect_all">Unselect all</string>
<string name="loading_backup">Loading backup…</string>
<string name="loading_packages">Loading packages…</string>
<string name="initializing">Initializing…</string>
<!-- Settings -->
<string name="settings_backup">Backup my data</string>

View file

@ -1,4 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
</resources>