Files
arcanechat-android/src/org/thoughtcrime/securesms/qr/BackupTransferActivity.java
T
B. Petersen 2e0ec41a37 fix leaving Delta Chat during backup transfer
this fixes leaving Delta Chat during backup transfer
by removing other activities that would abort BackupTransfer
by getting called with onNewIntent() otherwise.

moreover, the permantent notification is removed more reliably
and possible crashes in  the permantent notification closing (races ...)
are catched.

see code + comments for details.
2023-03-25 10:24:20 +01:00

237 lines
9.1 KiB
Java

package org.thoughtcrime.securesms.qr;
import android.content.Context;
import android.content.Intent;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AlertDialog;
import org.thoughtcrime.securesms.ApplicationPreferencesActivity;
import org.thoughtcrime.securesms.BaseActionBarActivity;
import org.thoughtcrime.securesms.ConversationListActivity;
import org.thoughtcrime.securesms.LogViewActivity;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.WebViewActivity;
import org.thoughtcrime.securesms.connect.DcHelper;
import org.thoughtcrime.securesms.service.GenericForegroundService;
import org.thoughtcrime.securesms.service.NotificationController;
import org.thoughtcrime.securesms.util.DynamicLanguage;
import org.thoughtcrime.securesms.util.DynamicTheme;
import org.thoughtcrime.securesms.util.Util;
public class BackupTransferActivity extends BaseActionBarActivity {
private final static String TAG = BackupTransferActivity.class.getSimpleName();
public enum TransferMode {
INVALID(0),
SENDER_SHOW_QR(1),
RECEIVER_SCAN_QR(2);
private final int i;
TransferMode(int i) { this.i = i; }
public int getInt() { return i; }
public static TransferMode fromInt(int i) { return values()[i]; }
};
public enum TransferState {
TRANSFER_UNKNOWN,
TRANSFER_ERROR,
TRANSFER_SUCCESS;
};
public static final String TRANSFER_MODE = "transfer_mode";
public static final String QR_CODE = "qr_code";
private TransferMode transferMode = TransferMode.RECEIVER_SCAN_QR;
private TransferState transferState = TransferState.TRANSFER_UNKNOWN;
private final DynamicTheme dynamicTheme = new DynamicTheme();
private final DynamicLanguage dynamicLanguage = new DynamicLanguage();
NotificationController notificationController;
private boolean notificationControllerClosed = false;
public boolean warnAboutCopiedQrCodeOnAbort = false;
@Override
protected void onCreate(Bundle icicle) {
super.onCreate(icicle);
dynamicTheme.onCreate(this);
dynamicLanguage.onCreate(this);
transferMode = TransferMode.fromInt(getIntent().getIntExtra(TRANSFER_MODE, TransferMode.INVALID.getInt()));
if (transferMode == TransferMode.INVALID) {
throw new RuntimeException("bad transfer mode");
}
DcHelper.getAccounts(this).stopIo();
String title = getString(transferMode == TransferMode.RECEIVER_SCAN_QR ? R.string.multidevice_reveiver_title : R.string.multidevice_title);
notificationController = GenericForegroundService.startForegroundTask(this, title);
setContentView(R.layout.backup_provider_activity);
switch(transferMode) {
case SENDER_SHOW_QR:
initFragment(android.R.id.content, new BackupProviderFragment(), dynamicLanguage.getCurrentLocale(), icicle);
break;
case RECEIVER_SCAN_QR:
initFragment(android.R.id.content, new BackupReceiverFragment(), dynamicLanguage.getCurrentLocale(), icicle);
break;
}
ActionBar supportActionBar = getSupportActionBar();
supportActionBar.setDisplayHomeAsUpEnabled(true);
supportActionBar.setHomeAsUpIndicator(R.drawable.ic_close_white_24dp);
supportActionBar.setTitle(title);
}
@Override
protected void onDestroy() {
super.onDestroy();
if (!notificationControllerClosed) {
notificationController.close();
}
DcHelper.getAccounts(this).startIo();
}
@Override
protected void onResume() {
super.onResume();
dynamicTheme.onResume(this);
dynamicLanguage.onResume(this);
}
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
menu.clear();
getMenuInflater().inflate(R.menu.backup_transfer_menu, menu);
return super.onPrepareOptionsMenu(menu);
}
@Override
public void onBackPressed() {
finishOrAskToFinish();
}
@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
super.onOptionsItemSelected(item);
switch (item.getItemId()) {
case android.R.id.home:
finishOrAskToFinish();
return true;
case R.id.troubleshooting:
// once help is evolved, it may be a more visible button, may be localized, may be offline
WebViewActivity.openUrlInBrowser(this, "https://delta.chat/en/help#multiclient");
return true;
case R.id.view_log_button:
startActivity(new Intent(this, LogViewActivity.class));
return true;
}
return false;
}
public void setTransferState(TransferState transferState) {
this.transferState = transferState;
}
private void finishOrAskToFinish() {
switch (transferState) {
case TRANSFER_ERROR:
case TRANSFER_SUCCESS:
doFinish();
break;
default:
String msg = getString(R.string.multidevice_abort);
if (warnAboutCopiedQrCodeOnAbort) {
msg += "\n\n" + getString(R.string.multidevice_abort_will_invalidate_copied_qr);
}
new AlertDialog.Builder(this)
.setMessage(msg)
.setPositiveButton(android.R.string.ok, (dialogInterface, i) -> doFinish())
.setNegativeButton(R.string.cancel, null)
.show();
break;
}
}
public void doFinish() {
// the permanent notification will prevent other activities to be started and kill BackupTransferActivity;
// close it before starting other activities
notificationController.close();
notificationControllerClosed = true;
if (transferMode == TransferMode.RECEIVER_SCAN_QR && transferState == TransferState.TRANSFER_SUCCESS) {
startActivity(new Intent(getApplicationContext(), ConversationListActivity.class));
} else if (transferMode == TransferMode.SENDER_SHOW_QR) {
// restart the activities that were removed when BackupTransferActivity was started at (**2)
// (we removed the activity backstack as otherwise a tap on the Delta Chat icon on the home screen would
// call onNewIntent() which cannot be aborted and will kill BackupTransferActivity.
// if all activities are removed, onCreate() will be called and that can be aborted, so that
// a tap in the home icon just opens BackupTransferActivity.
// (the user can leave Delta Chat during backup transfer :)
// a proper fix would maybe to not rely onNewIntent() at all - but that would require more refactorings
// and needs lots if testing in complicated areas (share ...))
startActivity(new Intent(getApplicationContext(), ConversationListActivity.class));
startActivity(new Intent(this, ApplicationPreferencesActivity.class));
overridePendingTransition(0, 0);
}
finish();
}
public void showLastErrorAlert(@NonNull String errorContext) {
String lastError = DcHelper.getContext(this).getLastError();
if (lastError.isEmpty()) {
lastError = "<last error not set>";
}
String error = errorContext;
if (!error.isEmpty()) {
error += ": ";
}
error += lastError;
new AlertDialog.Builder(this)
.setMessage(error)
.setPositiveButton(android.R.string.ok, null)
.setCancelable(false)
.show();
}
public void appendSSID(final TextView textView) {
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
new Thread(() -> {
try {
// depending on the android version, getting the SSID requires none, all or one of
// ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION, ACCESS_WIFI_STATE, ACCESS_NETWORK_STATE and maybe even more.
final WifiManager wifiManager = (WifiManager)getApplicationContext().getSystemService(Context.WIFI_SERVICE);
if (wifiManager.isWifiEnabled()) {
final WifiInfo info = wifiManager.getConnectionInfo();
final String ssid = info.getSSID();
Log.i(TAG, "wifi ssid: "+ssid);
if (!ssid.equals("<unknown ssid>")) { // "<unknown ssid>" may be returned on insufficient rights
Util.runOnMain(() -> {
textView.setText(textView.getText() + " (" + ssid + ")");
});
}
}
} catch (Exception e) {
e.printStackTrace();
}
}).start();
}
}
}