ImportBackupActivity.java

  1package eu.siacs.conversations.ui;
  2
  3import android.content.ComponentName;
  4import android.content.Context;
  5import android.content.DialogInterface;
  6import android.content.Intent;
  7import android.content.ServiceConnection;
  8import android.net.Uri;
  9import android.os.Bundle;
 10import android.os.IBinder;
 11import android.util.Log;
 12import android.view.LayoutInflater;
 13import android.view.Menu;
 14import android.view.MenuItem;
 15import android.view.View;
 16
 17import androidx.appcompat.app.AlertDialog;
 18import androidx.core.content.ContextCompat;
 19import androidx.databinding.DataBindingUtil;
 20
 21import com.google.android.material.snackbar.Snackbar;
 22
 23import java.io.IOException;
 24import java.util.List;
 25
 26import eu.siacs.conversations.Config;
 27import eu.siacs.conversations.R;
 28import eu.siacs.conversations.databinding.ActivityImportBackupBinding;
 29import eu.siacs.conversations.databinding.DialogEnterPasswordBinding;
 30import eu.siacs.conversations.services.ImportBackupService;
 31import eu.siacs.conversations.ui.adapter.BackupFileAdapter;
 32import eu.siacs.conversations.ui.util.SettingsUtils;
 33import eu.siacs.conversations.utils.BackupFileHeader;
 34import eu.siacs.conversations.utils.ThemeHelper;
 35
 36public class ImportBackupActivity extends ActionBarActivity implements ServiceConnection, ImportBackupService.OnBackupFilesLoaded, BackupFileAdapter.OnItemClickedListener, ImportBackupService.OnBackupProcessed {
 37
 38    private ActivityImportBackupBinding binding;
 39
 40    private BackupFileAdapter backupFileAdapter;
 41    private ImportBackupService service;
 42
 43    private boolean mLoadingState = false;
 44
 45    private int mTheme;
 46
 47    @Override
 48    protected void onCreate(final Bundle savedInstanceState) {
 49        this.mTheme = ThemeHelper.find(this);
 50        setTheme(this.mTheme);
 51        super.onCreate(savedInstanceState);
 52        binding = DataBindingUtil.setContentView(this, R.layout.activity_import_backup);
 53        setSupportActionBar(binding.toolbar);
 54        setLoadingState(savedInstanceState != null && savedInstanceState.getBoolean("loading_state", false));
 55        this.backupFileAdapter = new BackupFileAdapter();
 56        this.binding.list.setAdapter(this.backupFileAdapter);
 57        this.backupFileAdapter.setOnItemClickedListener(this);
 58    }
 59    
 60    @Override
 61    protected void onResume(){
 62        super.onResume();
 63        SettingsUtils.applyScreenshotPreventionSetting(this);
 64    }
 65
 66    @Override
 67    public boolean onCreateOptionsMenu(final Menu menu) {
 68        getMenuInflater().inflate(R.menu.import_backup, menu);
 69        final MenuItem openBackup = menu.findItem(R.id.action_open_backup_file);
 70        openBackup.setVisible(!this.mLoadingState);
 71        return true;
 72    }
 73
 74    @Override
 75    public void onSaveInstanceState(Bundle bundle) {
 76        bundle.putBoolean("loading_state", this.mLoadingState);
 77        super.onSaveInstanceState(bundle);
 78    }
 79
 80    @Override
 81    public void onStart() {
 82        super.onStart();
 83        final int theme = ThemeHelper.find(this);
 84        if (this.mTheme != theme) {
 85            recreate();
 86        } else {
 87            bindService(new Intent(this, ImportBackupService.class), this, Context.BIND_AUTO_CREATE);
 88        }
 89        final Intent intent = getIntent();
 90        if (intent != null && Intent.ACTION_VIEW.equals(intent.getAction()) && !this.mLoadingState) {
 91            Uri uri = intent.getData();
 92            if (uri != null) {
 93                openBackupFileFromUri(uri, true);
 94            }
 95        }
 96    }
 97
 98    @Override
 99    public void onStop() {
100        super.onStop();
101        if (this.service != null) {
102            this.service.removeOnBackupProcessedListener(this);
103        }
104        unbindService(this);
105    }
106
107    @Override
108    public void onServiceConnected(ComponentName name, IBinder service) {
109        ImportBackupService.ImportBackupServiceBinder binder = (ImportBackupService.ImportBackupServiceBinder) service;
110        this.service = binder.getService();
111        this.service.addOnBackupProcessedListener(this);
112        setLoadingState(this.service.getLoadingState());
113        this.service.loadBackupFiles(this);
114    }
115
116    @Override
117    public void onServiceDisconnected(ComponentName name) {
118        this.service = null;
119    }
120
121    @Override
122    public void onBackupFilesLoaded(final List<ImportBackupService.BackupFile> files) {
123        runOnUiThread(() -> backupFileAdapter.setFiles(files));
124    }
125
126    @Override
127    public void onClick(final ImportBackupService.BackupFile backupFile) {
128        showEnterPasswordDialog(backupFile, false);
129    }
130
131    private void openBackupFileFromUri(final Uri uri, final boolean finishOnCancel) {
132        try {
133            final ImportBackupService.BackupFile backupFile = ImportBackupService.BackupFile.read(this, uri);
134            showEnterPasswordDialog(backupFile, finishOnCancel);
135        } catch (final BackupFileHeader.OutdatedBackupFileVersion e) {
136            Snackbar.make(binding.coordinator, R.string.outdated_backup_file_format, Snackbar.LENGTH_LONG).show();
137        } catch (final IOException | IllegalArgumentException e) {
138            Log.d(Config.LOGTAG, "unable to open backup file " + uri, e);
139            Snackbar.make(binding.coordinator, R.string.not_a_backup_file, Snackbar.LENGTH_LONG).show();
140        } catch (final SecurityException e) {
141            Snackbar.make(binding.coordinator, R.string.sharing_application_not_grant_permission, Snackbar.LENGTH_LONG).show();
142        }
143    }
144
145    private void showEnterPasswordDialog(final ImportBackupService.BackupFile backupFile, final boolean finishOnCancel) {
146        final DialogEnterPasswordBinding enterPasswordBinding = DataBindingUtil.inflate(LayoutInflater.from(this), R.layout.dialog_enter_password, null, false);
147        Log.d(Config.LOGTAG, "attempting to import " + backupFile.getUri());
148        enterPasswordBinding.explain.setText(getString(R.string.enter_password_to_restore, backupFile.getHeader().getJid().toString()));
149        AlertDialog.Builder builder = new AlertDialog.Builder(this);
150        builder.setView(enterPasswordBinding.getRoot());
151        builder.setTitle(R.string.enter_password);
152        builder.setNegativeButton(R.string.cancel, (dialog, which) -> {
153            if (finishOnCancel) {
154                finish();
155            }
156        });
157        builder.setPositiveButton(R.string.restore, null);
158        builder.setCancelable(false);
159        final AlertDialog dialog = builder.create();
160        dialog.setOnShowListener((d) -> {
161            dialog.getButton(DialogInterface.BUTTON_POSITIVE).setOnClickListener(v -> {
162                final String password = enterPasswordBinding.accountPassword.getEditableText().toString();
163                if (password.isEmpty()) {
164                    enterPasswordBinding.accountPasswordLayout.setError(getString(R.string.please_enter_password));
165                    return;
166                }
167                final Uri uri = backupFile.getUri();
168                Intent intent = new Intent(this, ImportBackupService.class);
169                intent.setAction(Intent.ACTION_SEND);
170                intent.putExtra("password", password);
171                if ("file".equals(uri.getScheme())) {
172                    intent.putExtra("file", uri.getPath());
173                } else {
174                    intent.setData(uri);
175                    intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
176                }
177                setLoadingState(true);
178                ContextCompat.startForegroundService(this, intent);
179                d.dismiss();
180            });
181        });
182        dialog.show();
183    }
184
185    private void setLoadingState(final boolean loadingState) {
186        binding.coordinator.setVisibility(loadingState ? View.GONE : View.VISIBLE);
187        binding.inProgress.setVisibility(loadingState ? View.VISIBLE : View.GONE);
188        setTitle(loadingState ? R.string.restoring_backup : R.string.restore_backup);
189        configureActionBar(getSupportActionBar(), !loadingState);
190        this.mLoadingState = loadingState;
191        invalidateOptionsMenu();
192    }
193
194    @Override
195    public void onActivityResult(int requestCode, int resultCode, Intent intent) {
196        super.onActivityResult(requestCode, resultCode, intent);
197        if (resultCode == RESULT_OK) {
198            if (requestCode == 0xbac) {
199                openBackupFileFromUri(intent.getData(), false);
200            }
201        }
202    }
203
204    @Override
205    public void onAccountAlreadySetup() {
206        runOnUiThread(() -> {
207            setLoadingState(false);
208            Snackbar.make(binding.coordinator, R.string.account_already_setup, Snackbar.LENGTH_LONG).show();
209        });
210    }
211
212    @Override
213    public void onBackupRestored() {
214        runOnUiThread(() -> {
215            Intent intent = new Intent(this, ConversationActivity.class);
216            intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
217            startActivity(intent);
218            finish();
219        });
220    }
221
222    @Override
223    public void onBackupDecryptionFailed() {
224        runOnUiThread(() -> {
225            setLoadingState(false);
226            Snackbar.make(binding.coordinator, R.string.unable_to_decrypt_backup, Snackbar.LENGTH_LONG).show();
227        });
228    }
229
230    @Override
231    public void onBackupRestoreFailed() {
232        runOnUiThread(() -> {
233            setLoadingState(false);
234            Snackbar.make(binding.coordinator, R.string.unable_to_restore_backup, Snackbar.LENGTH_LONG).show();
235        });
236    }
237
238    @Override
239    public boolean onOptionsItemSelected(MenuItem item) {
240        if (item.getItemId() == R.id.action_open_backup_file) {
241            openBackupFile();
242            return true;
243        }
244        return super.onOptionsItemSelected(item);
245    }
246
247    private void openBackupFile() {
248        final Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
249        intent.setType("*/*");
250        intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, false);
251        intent.addCategory(Intent.CATEGORY_OPENABLE);
252        startActivityForResult(Intent.createChooser(intent, getString(R.string.open_backup)), 0xbac);
253    }
254}