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