diff options
author | Christian Schneppe <christian@pix-art.de> | 2019-01-26 15:07:28 +0100 |
---|---|---|
committer | Christian Schneppe <christian@pix-art.de> | 2019-01-26 15:07:28 +0100 |
commit | f2d502518ea3de673c7f0ebf425f53295f620f2f (patch) | |
tree | 2db8f4e334d51b59c35105bc1871b102f4bb34d3 /src/main/java/de/pixart/messenger/ui | |
parent | 2773c19c429c4bcb99fd0144cd1b3e2346cab962 (diff) |
rework backup & restore
use the implementation from Conversations
Diffstat (limited to 'src/main/java/de/pixart/messenger/ui')
9 files changed, 478 insertions, 398 deletions
diff --git a/src/main/java/de/pixart/messenger/ui/ConversationFragment.java b/src/main/java/de/pixart/messenger/ui/ConversationFragment.java index d7205506d..4f0486cf7 100644 --- a/src/main/java/de/pixart/messenger/ui/ConversationFragment.java +++ b/src/main/java/de/pixart/messenger/ui/ConversationFragment.java @@ -126,6 +126,9 @@ import rocks.xmpp.addr.Jid; import static de.pixart.messenger.ui.XmppActivity.EXTRA_ACCOUNT; import static de.pixart.messenger.ui.XmppActivity.REQUEST_INVITE_TO_CONVERSATION; import static de.pixart.messenger.ui.util.SoftKeyboardUtils.hideSoftKeyboard; +import static de.pixart.messenger.utils.PermissionUtils.allGranted; +import static de.pixart.messenger.utils.PermissionUtils.getFirstDenied; +import static de.pixart.messenger.utils.PermissionUtils.writeGranted; import static de.pixart.messenger.xmpp.Patches.ENCRYPTION_EXCEPTIONS; public class ConversationFragment extends XmppFragment implements EditMessage.KeyboardListener, MessageAdapter.OnContactPictureLongClicked, MessageAdapter.OnContactPictureClicked { @@ -596,33 +599,6 @@ public class ConversationFragment extends XmppFragment implements EditMessage.Ke return getConversation(activity, R.id.main_fragment); } - private static boolean allGranted(int[] grantResults) { - for (int grantResult : grantResults) { - if (grantResult != PackageManager.PERMISSION_GRANTED) { - return false; - } - } - return true; - } - - private static boolean writeGranted(int[] grantResults, String[] permission) { - for (int i = 0; i < grantResults.length; ++i) { - if (Manifest.permission.WRITE_EXTERNAL_STORAGE.equals(permission[i])) { - return grantResults[i] == PackageManager.PERMISSION_GRANTED; - } - } - return false; - } - - private static String getFirstDenied(int[] grantResults, String[] permissions) { - for (int i = 0; i < grantResults.length; ++i) { - if (grantResults[i] == PackageManager.PERMISSION_DENIED) { - return permissions[i]; - } - } - return null; - } - private static boolean scrolledToBottom(AbsListView listView) { final int count = listView.getCount(); if (count == 0) { diff --git a/src/main/java/de/pixart/messenger/ui/EditAccountActivity.java b/src/main/java/de/pixart/messenger/ui/EditAccountActivity.java index d04289d22..beddb195d 100644 --- a/src/main/java/de/pixart/messenger/ui/EditAccountActivity.java +++ b/src/main/java/de/pixart/messenger/ui/EditAccountActivity.java @@ -16,6 +16,7 @@ import android.preference.PreferenceManager; import android.provider.Settings; import android.security.KeyChain; import android.security.KeyChainAliasCallback; +import android.support.annotation.NonNull; import android.support.design.widget.TextInputLayout; import android.support.v4.content.ContextCompat; import android.support.v7.app.ActionBar; @@ -82,6 +83,9 @@ import de.pixart.messenger.xmpp.forms.Data; import de.pixart.messenger.xmpp.pep.Avatar; import rocks.xmpp.addr.Jid; +import static de.pixart.messenger.utils.PermissionUtils.allGranted; +import static de.pixart.messenger.utils.PermissionUtils.writeGranted; + public class EditAccountActivity extends OmemoActivity implements OnAccountUpdate, OnUpdateBlocklist, OnKeyStatusUpdated, OnCaptchaRequested, KeyChainAliasCallback, XmppConnectionService.OnShowErrorToast, XmppConnectionService.OnMamPreferencesFetched { @@ -90,6 +94,7 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat private static final int REQUEST_DATA_SAVER = 0xf244; private static final int REQUEST_CHANGE_STATUS = 0xee11; private static final int REQUEST_ORBOT = 0xff22; + private static final int REQUEST_IMPORT_BACKUP = 0x63fb; private AlertDialog mCaptchaDialog = null; private final AtomicBoolean mPendingReconnect = new AtomicBoolean(false); @@ -825,6 +830,12 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat return false; } switch (item.getItemId()) { + case R.id.action_import_backup: + if (hasStoragePermission(REQUEST_IMPORT_BACKUP)) { + startActivity(new Intent(this, ImportBackupActivity.class)); + } + overridePendingTransition(R.animator.fade_in, R.animator.fade_out); + break; case R.id.mgmt_account_reconnect: XmppConnection connection = mAccount.getXmppConnection(); if (connection != null) { @@ -1444,6 +1455,26 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat } @Override + public void onRequestPermissionsResult(int requestCode, @NonNull String permissions[], @NonNull int[] grantResults) { + if (grantResults.length > 0) { + if (allGranted(grantResults)) { + switch (requestCode) { + case REQUEST_IMPORT_BACKUP: + startActivity(new Intent(this, ImportBackupActivity.class)); + break; + } + } else { + Toast.makeText(this, R.string.no_storage_permission, Toast.LENGTH_SHORT).show(); + } + } + if (writeGranted(grantResults, permissions)) { + if (xmppConnectionService != null) { + xmppConnectionService.restartFileObserver(); + } + } + } + + @Override public void OnUpdateBlocklist(Status status) { if (isFinishing()) { return; diff --git a/src/main/java/de/pixart/messenger/ui/ImportBackupActivity.java b/src/main/java/de/pixart/messenger/ui/ImportBackupActivity.java new file mode 100644 index 000000000..f1c9eea25 --- /dev/null +++ b/src/main/java/de/pixart/messenger/ui/ImportBackupActivity.java @@ -0,0 +1,124 @@ +package de.pixart.messenger.ui; + +import android.content.ComponentName; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.ServiceConnection; +import android.databinding.DataBindingUtil; +import android.os.Bundle; +import android.os.IBinder; +import android.support.design.widget.Snackbar; +import android.support.v4.content.ContextCompat; +import android.support.v7.app.AlertDialog; +import android.support.v7.widget.Toolbar; +import android.util.Log; +import android.view.LayoutInflater; +import android.widget.Toast; + +import java.util.List; + +import de.pixart.messenger.Config; +import de.pixart.messenger.R; +import de.pixart.messenger.databinding.ActivityImportBackupBinding; +import de.pixart.messenger.databinding.DialogEnterPasswordBinding; +import de.pixart.messenger.services.ImportBackupService; +import de.pixart.messenger.ui.adapter.BackupFileAdapter; + +public class ImportBackupActivity extends ActionBarActivity implements ServiceConnection, ImportBackupService.OnBackupFilesLoaded, BackupFileAdapter.OnItemClickedListener, ImportBackupService.OnBackupProcessed { + + private ActivityImportBackupBinding binding; + + private BackupFileAdapter backupFileAdapter; + private ImportBackupService service; + + @Override + protected void onCreate(final Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + binding = DataBindingUtil.setContentView(this, R.layout.activity_import_backup); + setSupportActionBar((Toolbar) binding.toolbar); + configureActionBar(getSupportActionBar()); + this.backupFileAdapter = new BackupFileAdapter(); + this.binding.list.setAdapter(this.backupFileAdapter); + this.backupFileAdapter.setOnItemClickedListener(this); + } + + @Override + public void onStart() { + super.onStart(); + bindService(new Intent(this, ImportBackupService.class), this, Context.BIND_AUTO_CREATE); + } + + @Override + public void onStop() { + super.onStop(); + if (this.service != null) { + this.service.removeOnBackupProcessedListener(this); + } + unbindService(this); + } + + @Override + public void onServiceConnected(ComponentName name, IBinder service) { + ImportBackupService.ImportBackupServiceBinder binder = (ImportBackupService.ImportBackupServiceBinder) service; + this.service = binder.getService(); + this.service.addOnBackupProcessedListener(this); + this.service.loadBackupFiles(this); + } + + @Override + public void onServiceDisconnected(ComponentName name) { + this.service = null; + } + + @Override + public void onBackupFilesLoaded(final List<ImportBackupService.BackupFile> files) { + runOnUiThread(() -> { + backupFileAdapter.setFiles(files); + }); + } + + @Override + public void onClick(ImportBackupService.BackupFile backupFile) { + final DialogEnterPasswordBinding enterPasswordBinding = DataBindingUtil.inflate(LayoutInflater.from(this), R.layout.dialog_enter_password, null, false); + Log.d(Config.LOGTAG, "attempting to import " + backupFile.getFile().getAbsolutePath()); + enterPasswordBinding.explain.setText(getString(R.string.enter_password_to_restore, backupFile.getHeader().getJid().toString())); + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setView(enterPasswordBinding.getRoot()); + builder.setTitle(R.string.enter_password); + builder.setNegativeButton(R.string.cancel, null); + builder.setPositiveButton(R.string.restore, (dialog, which) -> { + final String password = enterPasswordBinding.accountPassword.getEditableText().toString(); + Intent intent = new Intent(this, ImportBackupService.class); + intent.putExtra("password", password); + intent.putExtra("file", backupFile.getFile().getAbsolutePath()); + ContextCompat.startForegroundService(this, intent); + }); + builder.setCancelable(false); + builder.create().show(); + } + + @Override + public void onBackupRestored() { + runOnUiThread(() -> { + Intent intent = new Intent(this, StartUI.class); + intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); + startActivity(intent); + finish(); + }); + } + + @Override + public void onBackupDecryptionFailed() { + runOnUiThread(() -> { + Snackbar.make(binding.coordinator, R.string.unable_to_decrypt_backup, Snackbar.LENGTH_LONG).show(); + }); + } + + @Override + public void onBackupRestoreFailed() { + runOnUiThread(() -> { + Snackbar.make(binding.coordinator, R.string.unable_to_restore_backup, Snackbar.LENGTH_LONG).show(); + }); + } +}
\ No newline at end of file diff --git a/src/main/java/de/pixart/messenger/ui/ManageAccountActivity.java b/src/main/java/de/pixart/messenger/ui/ManageAccountActivity.java index 607e2626d..a09a285f2 100644 --- a/src/main/java/de/pixart/messenger/ui/ManageAccountActivity.java +++ b/src/main/java/de/pixart/messenger/ui/ManageAccountActivity.java @@ -5,6 +5,7 @@ import android.content.Intent; import android.os.Bundle; import android.security.KeyChain; import android.security.KeyChainAliasCallback; +import android.support.annotation.NonNull; import android.support.v7.app.ActionBar; import android.support.v7.app.AlertDialog; import android.util.Pair; @@ -35,10 +36,15 @@ import de.pixart.messenger.utils.MenuDoubleTabUtil; import de.pixart.messenger.xmpp.XmppConnection; import rocks.xmpp.addr.Jid; +import static de.pixart.messenger.utils.PermissionUtils.allGranted; +import static de.pixart.messenger.utils.PermissionUtils.writeGranted; + public class ManageAccountActivity extends XmppActivity implements OnAccountUpdate, KeyChainAliasCallback, XmppConnectionService.OnAccountCreated, AccountAdapter.OnTglAccountState { private final String STATE_SELECTED_ACCOUNT = "selected_account"; + private static final int REQUEST_IMPORT_BACKUP = 0x63fb; + protected Account selectedAccount = null; protected Jid selectedAccountJid = null; @@ -75,7 +81,6 @@ public class ManageAccountActivity extends XmppActivity implements OnAccountUpda super.onCreate(savedInstanceState); setContentView(R.layout.activity_manage_accounts); - setSupportActionBar(findViewById(R.id.toolbar)); configureActionBar(getSupportActionBar()); if (savedInstanceState != null) { @@ -156,6 +161,7 @@ public class ManageAccountActivity extends XmppActivity implements OnAccountUpda addAccount.setVisible(false); addAccountWithCertificate.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS); } + return true; } @@ -187,7 +193,13 @@ public class ManageAccountActivity extends XmppActivity implements OnAccountUpda } switch (item.getItemId()) { case R.id.action_add_account: - startActivity(new Intent(getApplicationContext(), EditAccountActivity.class)); + startActivity(new Intent(this, EditAccountActivity.class)); + overridePendingTransition(R.animator.fade_in, R.animator.fade_out); + break; + case R.id.action_import_backup: + if (hasStoragePermission(REQUEST_IMPORT_BACKUP)) { + startActivity(new Intent(this, ImportBackupActivity.class)); + } overridePendingTransition(R.animator.fade_in, R.animator.fade_out); break; case R.id.action_add_account_with_cert: @@ -200,6 +212,26 @@ public class ManageAccountActivity extends XmppActivity implements OnAccountUpda } @Override + public void onRequestPermissionsResult(int requestCode, @NonNull String permissions[], @NonNull int[] grantResults) { + if (grantResults.length > 0) { + if (allGranted(grantResults)) { + switch (requestCode) { + case REQUEST_IMPORT_BACKUP: + startActivity(new Intent(this, ImportBackupActivity.class)); + break; + } + } else { + Toast.makeText(this, R.string.no_storage_permission, Toast.LENGTH_SHORT).show(); + } + } + if (writeGranted(grantResults, permissions)) { + if (xmppConnectionService != null) { + xmppConnectionService.restartFileObserver(); + } + } + } + + @Override public boolean onNavigateUp() { if (xmppConnectionService.getConversations().size() == 0) { Intent contactsIntent = new Intent(this, diff --git a/src/main/java/de/pixart/messenger/ui/SettingsActivity.java b/src/main/java/de/pixart/messenger/ui/SettingsActivity.java index 9c45d01b8..3eb01eb83 100644 --- a/src/main/java/de/pixart/messenger/ui/SettingsActivity.java +++ b/src/main/java/de/pixart/messenger/ui/SettingsActivity.java @@ -36,7 +36,8 @@ import de.pixart.messenger.Config; import de.pixart.messenger.R; import de.pixart.messenger.crypto.OmemoSetting; import de.pixart.messenger.entities.Account; -import de.pixart.messenger.services.ExportLogsService; +import de.pixart.messenger.persistance.FileBackend; +import de.pixart.messenger.services.ExportBackupService; import de.pixart.messenger.services.MemorizingTrustManager; import de.pixart.messenger.ui.util.StyledAttributes; import de.pixart.messenger.utils.Compatibility; @@ -64,7 +65,7 @@ public class SettingsActivity extends XmppActivity implements public static final String NUMBER_OF_ACCOUNTS = "number_of_accounts"; public static final String PLAY_GIF_INSIDE = "play_gif_inside"; - public static final int REQUEST_WRITE_LOGS = 0xbf8701; + public static final int REQUEST_CREATE_BACKUP = 0xbf8701; Preference multiAccountPreference; Preference BundledEmojiPreference; Preference QuickShareAttachmentChoicePreference; @@ -249,11 +250,12 @@ public class SettingsActivity extends XmppActivity implements }); } - final Preference exportLogsPreference = mSettingsFragment.findPreference("export_logs"); - if (exportLogsPreference != null) { - exportLogsPreference.setOnPreferenceClickListener(preference -> { - if (hasStoragePermission(REQUEST_WRITE_LOGS)) { - startExport(); + final Preference createBackupPreference = mSettingsFragment.findPreference("create_backup"); + if (createBackupPreference != null) { + createBackupPreference.setSummary(getString(R.string.pref_create_backup_summary, FileBackend.getBackupDirectory())); + createBackupPreference.setOnPreferenceClickListener(preference -> { + if (hasStoragePermission(REQUEST_CREATE_BACKUP)) { + createBackup(); } return true; }); @@ -538,18 +540,19 @@ public class SettingsActivity extends XmppActivity implements @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { - if (grantResults.length > 0) + if (grantResults.length > 0) { if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { - if (requestCode == REQUEST_WRITE_LOGS) { - startExport(); + if (requestCode == REQUEST_CREATE_BACKUP) { + createBackup(); } } else { Toast.makeText(this, R.string.no_storage_permission, Toast.LENGTH_SHORT).show(); } + } } - private void startExport() { - Compatibility.startService(this, new Intent(this, ExportLogsService.class)); + private void createBackup() { + ContextCompat.startForegroundService(this, new Intent(this, ExportBackupService.class)); } private void displayToast(final String msg) { diff --git a/src/main/java/de/pixart/messenger/ui/UriHandlerActivity.java b/src/main/java/de/pixart/messenger/ui/UriHandlerActivity.java index 559e20648..f5a5fb14f 100644 --- a/src/main/java/de/pixart/messenger/ui/UriHandlerActivity.java +++ b/src/main/java/de/pixart/messenger/ui/UriHandlerActivity.java @@ -86,7 +86,7 @@ public class UriHandlerActivity extends AppCompatActivity { private void handleUri(Uri uri, final boolean scanned) { final Intent intent; final XmppUri xmppUri = new XmppUri(uri); - final List<Jid> accounts = DatabaseBackend.getInstance(this).getAccountJids(); //TODO only look at enabled accounts + final List<Jid> accounts = DatabaseBackend.getInstance(this).getAccountJids(true); if (accounts.size() == 0) { if (xmppUri.isJidValid()) { intent = SignupUtils.getSignUpIntent(this); diff --git a/src/main/java/de/pixart/messenger/ui/WelcomeActivity.java b/src/main/java/de/pixart/messenger/ui/WelcomeActivity.java index 75493d6c8..0ce07dda4 100644 --- a/src/main/java/de/pixart/messenger/ui/WelcomeActivity.java +++ b/src/main/java/de/pixart/messenger/ui/WelcomeActivity.java @@ -10,6 +10,7 @@ import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteException; import android.os.Build; import android.os.Bundle; +import android.support.annotation.NonNull; import android.support.v7.app.ActionBar; import android.support.v7.app.AlertDialog; import android.support.v7.app.AppCompatActivity; @@ -41,9 +42,12 @@ import de.pixart.messenger.persistance.FileBackend; import de.pixart.messenger.utils.EncryptDecryptFile; import de.pixart.messenger.utils.XmppUri; +import static de.pixart.messenger.utils.PermissionUtils.allGranted; +import static de.pixart.messenger.utils.PermissionUtils.writeGranted; + public class WelcomeActivity extends XmppActivity { - boolean importSuccessful = false; + private static final int REQUEST_IMPORT_BACKUP = 0x63fb; @Override protected void refreshUiReal() { @@ -85,21 +89,14 @@ public class WelcomeActivity extends XmppActivity { ab.setDisplayHomeAsUpEnabled(false); } - //check if there is a backed up database -- - if (hasStoragePermission(REQUEST_READ_EXTERNAL_STORAGE)) { - BackupAvailable(); - } - - final Button ImportDatabase = findViewById(R.id.import_database); final TextView ImportText = findViewById(R.id.import_text); - - if (BackupAvailable() != 0) { + if (hasStoragePermission(REQUEST_IMPORT_BACKUP)) { ImportDatabase.setVisibility(View.VISIBLE); ImportText.setVisibility(View.VISIBLE); } + ImportDatabase.setOnClickListener(v -> startActivity(new Intent(this, ImportBackupActivity.class))); - ImportDatabase.setOnClickListener(v -> enterPasswordDialog(BackupAvailable())); final Button createAccount = findViewById(R.id.create_account); createAccount.setOnClickListener(v -> { @@ -127,290 +124,34 @@ public class WelcomeActivity extends XmppActivity { } - public void enterPasswordDialog(final int backup_type) { - if (backup_type == 1) { - LayoutInflater li = LayoutInflater.from(WelcomeActivity.this); - View promptsView = li.inflate(R.layout.password, null); - final AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(WelcomeActivity.this); - alertDialogBuilder.setView(promptsView); - final EditText userInput = promptsView - .findViewById(R.id.password); - alertDialogBuilder.setTitle(R.string.enter_password); - alertDialogBuilder.setMessage(R.string.enter_account_password); - alertDialogBuilder - .setCancelable(false) - .setPositiveButton(R.string.ok, - new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int id) { - final String password = userInput.getText().toString(); - final ProgressDialog pd = ProgressDialog.show(WelcomeActivity.this, getString(R.string.please_wait), getString(R.string.databaseimport_started), true); - if (!password.isEmpty()) { - new Thread(new Runnable() { - @Override - public void run() { - try { - checkDatabase(password); - } catch (IOException e) { - e.printStackTrace(); - } catch (Exception e) { - e.printStackTrace(); - } - pd.dismiss(); - } - }).start(); - } else { - AlertDialog.Builder builder = new AlertDialog.Builder(WelcomeActivity.this); - builder.setTitle(R.string.error); - builder.setMessage(R.string.password_should_not_be_empty); - builder.setNegativeButton(R.string.cancel, null); - builder.setPositiveButton(R.string.try_again, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int id) { - enterPasswordDialog(backup_type); - } - }); - builder.create().show(); - } - } - }) - .setNegativeButton(R.string.cancel, - new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int id) { - Toast.makeText(WelcomeActivity.this, R.string.import_canceled, Toast.LENGTH_LONG).show(); - dialog.dismiss(); - } - } - ); - WelcomeActivity.this.runOnUiThread(new Runnable() { - public void run() { - // create alert dialog - AlertDialog alertDialog = alertDialogBuilder.create(); - // show it - alertDialog.show(); - } - }); - } else { - try { - checkDatabase(null); - } catch (IOException e) { - e.printStackTrace(); - } catch (Exception e) { - e.printStackTrace(); - } - } + public void addInviteUri(Intent intent) { + StartConversationActivity.addInviteUri(intent, getIntent()); } - private int BackupAvailable() { - // Set the folder on the SDcard - File filePath_enc = new File(FileBackend.getBackupDirectory() + "/database.db.crypt"); - File filePath_dec = new File(FileBackend.getBackupDirectory() + "/database.db"); - if (filePath_enc.exists()) { - Log.d(Config.LOGTAG, "DB Path existing (encrypted)"); - return 1; - } else if (filePath_dec.exists()) { - Log.d(Config.LOGTAG, "DB Path existing (decrypted)"); - return 2; - } else { - Log.d(Config.LOGTAG, "DB Path not existing"); - return 0; - } + public static void launch(AppCompatActivity activity) { + Intent intent = new Intent(activity, WelcomeActivity.class); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); + activity.startActivity(intent); + activity.overridePendingTransition(0, 0); } - private void checkDatabase(String DecryptionKey) throws IOException { - if (DecryptionKey != null) { - // Set the folder on the SDcard - File directory = new File(FileBackend.getBackupDirectory()); - // Set the input file stream up: - FileInputStream InputFile = new FileInputStream(directory.getPath() + "/database.db.crypt"); - // Temp output for DB checks - File TempFile = new File(directory.getPath() + "database.bak"); - FileOutputStream OutputTemp = new FileOutputStream(TempFile); - - try { - EncryptDecryptFile.decrypt(InputFile, OutputTemp, DecryptionKey); - } catch (NoSuchAlgorithmException e) { - Log.d(Config.LOGTAG, "Database importer: decryption failed with " + e); - e.printStackTrace(); - } catch (NoSuchPaddingException e) { - Log.d(Config.LOGTAG, "Database importer: decryption failed with " + e); - e.printStackTrace(); - } catch (InvalidKeyException e) { - Log.d(Config.LOGTAG, "Database importer: decryption failed (invalid key) with " + e); - e.printStackTrace(); - } catch (IOException e) { - Log.d(Config.LOGTAG, "Database importer: decryption failed (IO) with " + e); - e.printStackTrace(); - } catch (Exception e) { - Log.d(Config.LOGTAG, "Database importer: Error " + e); - e.printStackTrace(); - } - - SQLiteDatabase checkDB = null; - int DB_Version = DatabaseBackend.DATABASE_VERSION; - int Backup_DB_Version = 0; - - try { - String dbPath = TempFile.toString(); - checkDB = SQLiteDatabase.openDatabase(dbPath, null, SQLiteDatabase.OPEN_READONLY); - Backup_DB_Version = checkDB.getVersion(); - Log.d(Config.LOGTAG, "Backup found: " + checkDB + " Version: " + checkDB.getVersion()); - } catch (SQLiteException e) { - //database does't exist yet. - Log.d(Config.LOGTAG, "No backup found: " + checkDB); - } catch (Exception e) { - Log.d(Config.LOGTAG, "Error importing backup: " + e); - } - - if (checkDB != null) { - checkDB.close(); - } - if (checkDB != null) { - Log.d(Config.LOGTAG, "checkDB = " + checkDB.toString() + ", Backup DB = " + Backup_DB_Version + ", DB = " + DB_Version); - } - if (checkDB != null && Backup_DB_Version != 0 && Backup_DB_Version <= DB_Version) { - try { - ImportDatabase(); - importSuccessful = true; - } catch (Exception e) { - importSuccessful = false; - e.printStackTrace(); - } finally { - if (importSuccessful) { - restart(); - } - } - } else if (checkDB != null && Backup_DB_Version == 0) { - WelcomeActivity.this.runOnUiThread(new Runnable() { - public void run() { - Toast.makeText(WelcomeActivity.this, R.string.Password_wrong, Toast.LENGTH_LONG).show(); - enterPasswordDialog(1); - } - }); - } else { - WelcomeActivity.this.runOnUiThread(new Runnable() { - public void run() { - Toast.makeText(WelcomeActivity.this, R.string.Import_failed, Toast.LENGTH_LONG).show(); - } - }); - } - } else { - // Set the folder on the SDcard - File directory = new File(FileBackend.getBackupDirectory()); - // Set the input file stream up: - FileInputStream InputFile = new FileInputStream(directory.getPath() + "/database.db"); - // Temp output for DB checks - File TempFile = new File(directory.getPath() + "database.bak"); - FileOutputStream OutputTemp = new FileOutputStream(TempFile); - - try { - // Transfer bytes from in to out - byte[] buf = new byte[1024]; - int len; - while ((len = InputFile.read(buf)) > 0) { - OutputTemp.write(buf, 0, len); - } - } finally { - OutputTemp.close(); - } - - SQLiteDatabase checkDB = null; - int DB_Version = DatabaseBackend.DATABASE_VERSION; - int Backup_DB_Version = 0; - - try { - String dbPath = TempFile.toString(); - checkDB = SQLiteDatabase.openDatabase(dbPath, null, SQLiteDatabase.OPEN_READONLY); - Backup_DB_Version = checkDB.getVersion(); - Log.d(Config.LOGTAG, "Backup found: " + checkDB + " Version: " + checkDB.getVersion()); - } catch (SQLiteException e) { - //database does't exist yet. - Log.d(Config.LOGTAG, "No backup found: " + checkDB); - } catch (Exception e) { - Log.d(Config.LOGTAG, "Error importing backup: " + e); - } - - if (checkDB != null) { - checkDB.close(); - } - if (checkDB != null) { - Log.d(Config.LOGTAG, "checkDB = " + checkDB.toString() + ", Backup DB = " + Backup_DB_Version + ", DB = " + DB_Version); - } - if (checkDB != null && Backup_DB_Version != 0 && Backup_DB_Version <= DB_Version) { - try { - ImportDatabase(); - importSuccessful = true; - } catch (Exception e) { - importSuccessful = false; - e.printStackTrace(); - } finally { - if (importSuccessful) { - restart(); - } + @Override + public void onRequestPermissionsResult(int requestCode, @NonNull String permissions[], @NonNull int[] grantResults) { + if (grantResults.length > 0) { + if (allGranted(grantResults)) { + switch (requestCode) { + case REQUEST_IMPORT_BACKUP: + startActivity(new Intent(this, ImportBackupActivity.class)); + break; } } else { - WelcomeActivity.this.runOnUiThread(new Runnable() { - public void run() { - Toast.makeText(WelcomeActivity.this, R.string.Import_failed, Toast.LENGTH_LONG).show(); - } - }); + Toast.makeText(this, R.string.no_storage_permission, Toast.LENGTH_SHORT).show(); } } - } - - private void ImportDatabase() throws Exception { - // Set location for the db: - final OutputStream OutputFile = new FileOutputStream(this.getDatabasePath(DatabaseBackend.DATABASE_NAME)); - // Set the folder on the SDcard - File directory = new File(FileBackend.getBackupDirectory()); - // Set the input file stream up: - final InputStream InputFile = new FileInputStream(directory.getPath() + "database.bak"); - //set temp file - File TempFile = new File(directory.getPath() + "database.bak"); - - // Transfer bytes from the input file to the output file - byte[] buffer = new byte[1024]; - int length; - while ((length = InputFile.read(buffer)) > 0) { - OutputFile.write(buffer, 0, length); - } - if (TempFile.exists()) { - Log.d(Config.LOGTAG, "Delete temp file from " + TempFile.toString()); - TempFile.delete(); - } - } - - private void restart() { - //restart app - Log.d(Config.LOGTAG, "Restarting " + getBaseContext().getPackageManager().getLaunchIntentForPackage(getBaseContext().getPackageName())); - Intent intent = getBaseContext().getPackageManager().getLaunchIntentForPackage(getBaseContext().getPackageName()); - intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - startActivity(intent); - overridePendingTransition(R.animator.fade_in, R.animator.fade_out); - System.exit(0); - } - - public boolean hasStoragePermission(int requestCode) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - if (checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { - requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, requestCode); - return false; - } else { - return true; + if (writeGranted(grantResults, permissions)) { + if (xmppConnectionService != null) { + xmppConnectionService.restartFileObserver(); } - } else { - return true; } } - - public void addInviteUri(Intent intent) { - StartConversationActivity.addInviteUri(intent, getIntent()); - } - - public static void launch(AppCompatActivity activity) { - Intent intent = new Intent(activity, WelcomeActivity.class); - intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); - activity.startActivity(intent); - activity.overridePendingTransition(0, 0); - } }
\ No newline at end of file diff --git a/src/main/java/de/pixart/messenger/ui/adapter/AccountAdapter.java b/src/main/java/de/pixart/messenger/ui/adapter/AccountAdapter.java index 391fee0b9..e060d8828 100644 --- a/src/main/java/de/pixart/messenger/ui/adapter/AccountAdapter.java +++ b/src/main/java/de/pixart/messenger/ui/adapter/AccountAdapter.java @@ -1,19 +1,17 @@ package de.pixart.messenger.ui.adapter; -import android.content.Context; import android.content.res.Resources; +import android.databinding.DataBindingUtil; import android.graphics.Bitmap; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.os.AsyncTask; import android.support.annotation.NonNull; -import android.support.v7.widget.SwitchCompat; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ArrayAdapter; import android.widget.ImageView; -import android.widget.TextView; import java.lang.ref.WeakReference; import java.util.List; @@ -21,8 +19,8 @@ import java.util.concurrent.RejectedExecutionException; import de.pixart.messenger.Config; import de.pixart.messenger.R; +import de.pixart.messenger.databinding.AccountRowBinding; import de.pixart.messenger.entities.Account; -import de.pixart.messenger.ui.ManageAccountActivity; import de.pixart.messenger.ui.XmppActivity; import de.pixart.messenger.ui.util.StyledAttributes; import de.pixart.messenger.utils.UIHelper; @@ -44,47 +42,46 @@ public class AccountAdapter extends ArrayAdapter<Account> { this.showStateButton = true; } - @NonNull @Override public View getView(int position, View view, @NonNull ViewGroup parent) { final Account account = getItem(position); + final ViewHolder viewHolder; if (view == null) { - LayoutInflater inflater = (LayoutInflater) getContext() - .getSystemService(Context.LAYOUT_INFLATER_SERVICE); - view = inflater.inflate(R.layout.account_row, parent, false); + AccountRowBinding binding = DataBindingUtil.inflate(LayoutInflater.from(parent.getContext()), R.layout.account_row, parent, false); + view = binding.getRoot(); + viewHolder = new ViewHolder(binding); + view.setTag(viewHolder); + } else { + viewHolder = (ViewHolder) view.getTag(); } - TextView jid = view.findViewById(R.id.account_jid); if (Config.DOMAIN_LOCK != null) { - jid.setText(account.getJid().getLocal()); + viewHolder.binding.accountJid.setText(account.getJid().getLocal()); } else { - jid.setText(account.getJid().asBareJid().toString()); + viewHolder.binding.accountJid.setText(account.getJid().asBareJid().toString()); } - TextView statusView = view.findViewById(R.id.account_status); - ImageView imageView = view.findViewById(R.id.account_image); - loadAvatar(account,imageView); - statusView.setText(getContext().getString(account.getStatus().getReadableId())); + loadAvatar(account, viewHolder.binding.accountImage); + viewHolder.binding.accountStatus.setText(getContext().getString(account.getStatus().getReadableId())); switch (account.getStatus()) { case ONLINE: - statusView.setTextColor(StyledAttributes.getColor(activity, R.attr.TextColorOnline)); + viewHolder.binding.accountStatus.setTextColor(StyledAttributes.getColor(activity, R.attr.TextColorOnline)); break; case DISABLED: case CONNECTING: - statusView.setTextColor(StyledAttributes.getColor(activity, android.R.attr.textColorSecondary)); + viewHolder.binding.accountStatus.setTextColor(StyledAttributes.getColor(activity, android.R.attr.textColorSecondary)); break; default: - statusView.setTextColor(StyledAttributes.getColor(activity, R.attr.TextColorError)); + viewHolder.binding.accountStatus.setTextColor(StyledAttributes.getColor(activity, R.attr.TextColorError)); break; } - final SwitchCompat tglAccountState = view.findViewById(R.id.tgl_account_status); final boolean isDisabled = (account.getStatus() == Account.State.DISABLED); - tglAccountState.setOnCheckedChangeListener(null); - tglAccountState.setChecked(!isDisabled); + viewHolder.binding.tglAccountStatus.setOnCheckedChangeListener(null); + viewHolder.binding.tglAccountStatus.setChecked(!isDisabled); if (this.showStateButton) { - tglAccountState.setVisibility(View.VISIBLE); + viewHolder.binding.tglAccountStatus.setVisibility(View.VISIBLE); } else { - tglAccountState.setVisibility(View.GONE); + viewHolder.binding.tglAccountStatus.setVisibility(View.GONE); } - tglAccountState.setOnCheckedChangeListener((compoundButton, b) -> { + viewHolder.binding.tglAccountStatus.setOnCheckedChangeListener((compoundButton, b) -> { if (b == isDisabled && activity instanceof OnTglAccountState) { ((OnTglAccountState) activity).onClickTglAccountState(account, b); } @@ -92,6 +89,62 @@ public class AccountAdapter extends ArrayAdapter<Account> { return view; } + private static class ViewHolder { + private final AccountRowBinding binding; + + private ViewHolder(AccountRowBinding binding) { + this.binding = binding; + } + } + + class BitmapWorkerTask extends AsyncTask<Account, Void, Bitmap> { + private final WeakReference<ImageView> imageViewReference; + private Account account = null; + + public BitmapWorkerTask(ImageView imageView) { + imageViewReference = new WeakReference<>(imageView); + } + + @Override + protected Bitmap doInBackground(Account... params) { + this.account = params[0]; + return activity.avatarService().get(this.account, activity.getPixel(48), isCancelled()); + } + + @Override + protected void onPostExecute(Bitmap bitmap) { + if (bitmap != null && !isCancelled()) { + final ImageView imageView = imageViewReference.get(); + if (imageView != null) { + imageView.setImageBitmap(bitmap); + imageView.setBackgroundColor(0x00000000); + } + } + } + } + + public void loadAvatar(Account account, ImageView imageView) { + if (cancelPotentialWork(account, imageView)) { + final Bitmap bm = activity.avatarService().get(account, activity.getPixel(48), true); + if (bm != null) { + cancelPotentialWork(account, imageView); + imageView.setImageBitmap(bm); + imageView.setBackgroundColor(0x00000000); + } else { + imageView.setBackgroundColor(UIHelper.getColorForName(account.getJid().asBareJid().toString())); + imageView.setImageDrawable(null); + final BitmapWorkerTask task = new BitmapWorkerTask(imageView); + final AsyncDrawable asyncDrawable = new AsyncDrawable(activity.getResources(), null, task); + imageView.setImageDrawable(asyncDrawable); + try { + task.execute(account); + } catch (final RejectedExecutionException ignored) { + } + } + } + } + + public interface OnTglAccountState { void onClickTglAccountState(Account account, boolean state); } @@ -121,27 +174,6 @@ public class AccountAdapter extends ArrayAdapter<Account> { return null; } - public void loadAvatar(Account account, ImageView imageView) { - if (cancelPotentialWork(account, imageView)) { - final Bitmap bm = activity.avatarService().get(account, activity.getPixel(56), true); - if (bm != null) { - cancelPotentialWork(account, imageView); - imageView.setImageBitmap(bm); - imageView.setBackgroundColor(0x00000000); - } else { - imageView.setBackgroundColor(UIHelper.getColorForName(account.getJid().asBareJid().toString())); - imageView.setImageDrawable(null); - final BitmapWorkerTask task = new BitmapWorkerTask(imageView); - final AsyncDrawable asyncDrawable = new AsyncDrawable(activity.getResources(), null, task); - imageView.setImageDrawable(asyncDrawable); - try { - task.executeOnExecutor(BitmapWorkerTask.THREAD_POOL_EXECUTOR, account); - } catch (final RejectedExecutionException ignored) { - } - } - } - } - static class AsyncDrawable extends BitmapDrawable { private final WeakReference<BitmapWorkerTask> bitmapWorkerTaskReference; @@ -154,30 +186,4 @@ public class AccountAdapter extends ArrayAdapter<Account> { return bitmapWorkerTaskReference.get(); } } - - class BitmapWorkerTask extends AsyncTask<Account, Void, Bitmap> { - private final WeakReference<ImageView> imageViewReference; - private Account account = null; - - public BitmapWorkerTask(ImageView imageView) { - imageViewReference = new WeakReference<>(imageView); - } - - @Override - protected Bitmap doInBackground(Account... params) { - this.account = params[0]; - return activity.avatarService().get(this.account, activity.getPixel(56), isCancelled()); - } - - @Override - protected void onPostExecute(Bitmap bitmap) { - if (bitmap != null && !isCancelled()) { - final ImageView imageView = imageViewReference.get(); - if (imageView != null) { - imageView.setImageBitmap(bitmap); - imageView.setBackgroundColor(0x00000000); - } - } - } - } } diff --git a/src/main/java/de/pixart/messenger/ui/adapter/BackupFileAdapter.java b/src/main/java/de/pixart/messenger/ui/adapter/BackupFileAdapter.java new file mode 100644 index 000000000..84ae61e11 --- /dev/null +++ b/src/main/java/de/pixart/messenger/ui/adapter/BackupFileAdapter.java @@ -0,0 +1,167 @@ +package de.pixart.messenger.ui.adapter; + +import android.content.res.Resources; +import android.databinding.DataBindingUtil; +import android.graphics.Bitmap; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; +import android.os.AsyncTask; +import android.support.annotation.NonNull; +import android.support.v7.widget.RecyclerView; +import android.text.format.DateUtils; +import android.util.DisplayMetrics; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; + +import java.lang.ref.WeakReference; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.RejectedExecutionException; + +import de.pixart.messenger.R; +import de.pixart.messenger.databinding.AccountRowBinding; +import de.pixart.messenger.services.AvatarService; +import de.pixart.messenger.services.ImportBackupService; +import de.pixart.messenger.utils.BackupFileHeader; +import de.pixart.messenger.utils.UIHelper; +import rocks.xmpp.addr.Jid; + +public class BackupFileAdapter extends RecyclerView.Adapter<BackupFileAdapter.BackupFileViewHolder> { + + private OnItemClickedListener listener; + + private final List<ImportBackupService.BackupFile> files = new ArrayList<>(); + + + @NonNull + @Override + public BackupFileViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) { + return new BackupFileViewHolder(DataBindingUtil.inflate(LayoutInflater.from(viewGroup.getContext()), R.layout.account_row, viewGroup, false)); + } + + @Override + public void onBindViewHolder(@NonNull BackupFileViewHolder backupFileViewHolder, int position) { + final ImportBackupService.BackupFile backupFile = files.get(position); + final BackupFileHeader header = backupFile.getHeader(); + backupFileViewHolder.binding.accountJid.setText(header.getJid().asBareJid().toString()); + backupFileViewHolder.binding.accountStatus.setText(String.format("%s ยท %s", header.getApp(), DateUtils.formatDateTime(backupFileViewHolder.binding.getRoot().getContext(), header.getTimestamp(), DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_YEAR))); + backupFileViewHolder.binding.tglAccountStatus.setVisibility(View.GONE); + backupFileViewHolder.binding.getRoot().setOnClickListener(v -> { + if (listener != null) { + listener.onClick(backupFile); + } + }); + loadAvatar(header.getJid(), backupFileViewHolder.binding.accountImage); + } + + @Override + public int getItemCount() { + return files.size(); + } + + public void setFiles(List<ImportBackupService.BackupFile> files) { + this.files.clear(); + this.files.addAll(files); + notifyDataSetChanged(); + } + + public void setOnItemClickedListener(OnItemClickedListener listener) { + this.listener = listener; + } + + static class BackupFileViewHolder extends RecyclerView.ViewHolder { + private final AccountRowBinding binding; + + BackupFileViewHolder(AccountRowBinding binding) { + super(binding.getRoot()); + this.binding = binding; + } + } + + public interface OnItemClickedListener { + void onClick(ImportBackupService.BackupFile backupFile); + } + + static class BitmapWorkerTask extends AsyncTask<Jid, Void, Bitmap> { + private final WeakReference<ImageView> imageViewReference; + private Jid jid = null; + private final int size; + + BitmapWorkerTask(ImageView imageView) { + imageViewReference = new WeakReference<>(imageView); + DisplayMetrics metrics = imageView.getContext().getResources().getDisplayMetrics(); + this.size = ((int) (48 * metrics.density)); + } + + @Override + protected Bitmap doInBackground(Jid... params) { + this.jid = params[0]; + return AvatarService.get(this.jid, size); + } + + @Override + protected void onPostExecute(Bitmap bitmap) { + if (bitmap != null && !isCancelled()) { + final ImageView imageView = imageViewReference.get(); + if (imageView != null) { + imageView.setImageBitmap(bitmap); + imageView.setBackgroundColor(0x00000000); + } + } + } + } + + private void loadAvatar(Jid jid, ImageView imageView) { + if (cancelPotentialWork(jid, imageView)) { + imageView.setBackgroundColor(UIHelper.getColorForName(jid.asBareJid().toString())); + imageView.setImageDrawable(null); + final BitmapWorkerTask task = new BitmapWorkerTask(imageView); + final AsyncDrawable asyncDrawable = new AsyncDrawable(imageView.getContext().getResources(), null, task); + imageView.setImageDrawable(asyncDrawable); + try { + task.execute(jid); + } catch (final RejectedExecutionException ignored) { + } + } + } + + private static boolean cancelPotentialWork(Jid jid, ImageView imageView) { + final BitmapWorkerTask bitmapWorkerTask = getBitmapWorkerTask(imageView); + + if (bitmapWorkerTask != null) { + final Jid oldJid = bitmapWorkerTask.jid; + if (oldJid == null || jid != oldJid) { + bitmapWorkerTask.cancel(true); + } else { + return false; + } + } + return true; + } + + private static BitmapWorkerTask getBitmapWorkerTask(ImageView imageView) { + if (imageView != null) { + final Drawable drawable = imageView.getDrawable(); + if (drawable instanceof AsyncDrawable) { + final AsyncDrawable asyncDrawable = (AsyncDrawable) drawable; + return asyncDrawable.getBitmapWorkerTask(); + } + } + return null; + } + + static class AsyncDrawable extends BitmapDrawable { + private final WeakReference<BitmapWorkerTask> bitmapWorkerTaskReference; + + AsyncDrawable(Resources res, Bitmap bitmap, BitmapWorkerTask bitmapWorkerTask) { + super(res, bitmap); + bitmapWorkerTaskReference = new WeakReference<>(bitmapWorkerTask); + } + + BitmapWorkerTask getBitmapWorkerTask() { + return bitmapWorkerTaskReference.get(); + } + } +}
\ No newline at end of file |