From 835fd474823cf91395e4f3d2f19f47338bc66ca3 Mon Sep 17 00:00:00 2001 From: Cody Henthorne Date: Mon, 18 Sep 2023 15:33:24 -0400 Subject: [PATCH] Fix crashes related to activity starts. --- .../mediasend/v2/MediaSelectionViewModel.kt | 7 +- .../addmoney/PaymentsAddMoneyRepository.java | 32 --------- .../addmoney/PaymentsAddMoneyRepository.kt | 30 +++++++++ .../addmoney/PaymentsAddMoneyViewModel.java | 65 ------------------- .../addmoney/PaymentsAddMoneyViewModel.kt | 40 ++++++++++++ .../securesms/providers/BlobProvider.java | 28 +++++++- 6 files changed, 100 insertions(+), 102 deletions(-) delete mode 100644 app/src/main/java/org/thoughtcrime/securesms/payments/preferences/addmoney/PaymentsAddMoneyRepository.java create mode 100644 app/src/main/java/org/thoughtcrime/securesms/payments/preferences/addmoney/PaymentsAddMoneyRepository.kt delete mode 100644 app/src/main/java/org/thoughtcrime/securesms/payments/preferences/addmoney/PaymentsAddMoneyViewModel.java create mode 100644 app/src/main/java/org/thoughtcrime/securesms/payments/preferences/addmoney/PaymentsAddMoneyViewModel.kt diff --git a/app/src/main/java/org/thoughtcrime/securesms/mediasend/v2/MediaSelectionViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/mediasend/v2/MediaSelectionViewModel.kt index 9e993bc6ee..ff9444d22a 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/mediasend/v2/MediaSelectionViewModel.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/mediasend/v2/MediaSelectionViewModel.kt @@ -436,10 +436,9 @@ class MediaSelectionViewModel( val cameraFirstCapture: Media? = savedInstanceState.getParcelableCompat(STATE_CAMERA_FIRST_CAPTURE, Media::class.java) val editorCount: Int = savedInstanceState.getInt(STATE_EDITOR_COUNT, 0) val blobUri: Uri? = savedInstanceState.getParcelableCompat(STATE_EDITORS, Uri::class.java) - - val editorStates: List = if (editorCount > 0 && blobUri != null) { - val accumulator: MutableList = mutableListOf() - val blobProvider: BlobProvider = BlobProvider.getInstance() + val blobProvider: BlobProvider = BlobProvider.getInstance() + val editorStates: List = if (editorCount > 0 && blobUri != null && blobProvider.hasStream(context, blobUri)) { + val accumulator: MutableList = mutableListOf() val blob: ByteArray = ByteStreams.toByteArray(blobProvider.getStream(context, blobUri)) val parcel: Parcel = Parcel.obtain() parcel.unmarshall(blob, 0, blob.size) diff --git a/app/src/main/java/org/thoughtcrime/securesms/payments/preferences/addmoney/PaymentsAddMoneyRepository.java b/app/src/main/java/org/thoughtcrime/securesms/payments/preferences/addmoney/PaymentsAddMoneyRepository.java deleted file mode 100644 index 8025dcfdc0..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/payments/preferences/addmoney/PaymentsAddMoneyRepository.java +++ /dev/null @@ -1,32 +0,0 @@ -package org.thoughtcrime.securesms.payments.preferences.addmoney; - -import android.net.Uri; - -import androidx.annotation.MainThread; -import androidx.annotation.NonNull; - -import org.thoughtcrime.securesms.dependencies.ApplicationDependencies; -import org.thoughtcrime.securesms.keyvalue.SignalStore; -import org.thoughtcrime.securesms.payments.MobileCoinPublicAddress; -import org.thoughtcrime.securesms.util.AsynchronousCallback; - -final class PaymentsAddMoneyRepository { - - @MainThread - void getWalletAddress(@NonNull AsynchronousCallback.MainThread callback) { - if (!SignalStore.paymentsValues().mobileCoinPaymentsEnabled()) { - callback.onError(Error.PAYMENTS_NOT_ENABLED); - } - - MobileCoinPublicAddress publicAddress = ApplicationDependencies.getPayments().getWallet().getMobileCoinPublicAddress(); - String paymentAddressBase58 = publicAddress.getPaymentAddressBase58(); - Uri paymentAddressUri = publicAddress.getPaymentAddressUri(); - - callback.onComplete(new AddressAndUri(paymentAddressBase58, paymentAddressUri)); - } - - enum Error { - PAYMENTS_NOT_ENABLED - } - -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/payments/preferences/addmoney/PaymentsAddMoneyRepository.kt b/app/src/main/java/org/thoughtcrime/securesms/payments/preferences/addmoney/PaymentsAddMoneyRepository.kt new file mode 100644 index 0000000000..d1baf92704 --- /dev/null +++ b/app/src/main/java/org/thoughtcrime/securesms/payments/preferences/addmoney/PaymentsAddMoneyRepository.kt @@ -0,0 +1,30 @@ +package org.thoughtcrime.securesms.payments.preferences.addmoney + +import androidx.annotation.MainThread +import io.reactivex.rxjava3.core.Single +import io.reactivex.rxjava3.schedulers.Schedulers +import org.thoughtcrime.securesms.dependencies.ApplicationDependencies +import org.thoughtcrime.securesms.keyvalue.SignalStore +import org.signal.core.util.Result as SignalResult + +internal class PaymentsAddMoneyRepository { + @MainThread + fun getWalletAddress(): Single> { + if (!SignalStore.paymentsValues().mobileCoinPaymentsEnabled()) { + return Single.just(SignalResult.failure(Error.PAYMENTS_NOT_ENABLED)) + } + + return Single.fromCallable> { + val publicAddress = ApplicationDependencies.getPayments().wallet.mobileCoinPublicAddress + val paymentAddressBase58 = publicAddress.paymentAddressBase58 + val paymentAddressUri = publicAddress.paymentAddressUri + SignalResult.success(AddressAndUri(paymentAddressBase58, paymentAddressUri)) + } + .subscribeOn(Schedulers.io()) + .observeOn(Schedulers.io()) + } + + internal enum class Error { + PAYMENTS_NOT_ENABLED + } +} diff --git a/app/src/main/java/org/thoughtcrime/securesms/payments/preferences/addmoney/PaymentsAddMoneyViewModel.java b/app/src/main/java/org/thoughtcrime/securesms/payments/preferences/addmoney/PaymentsAddMoneyViewModel.java deleted file mode 100644 index d83ac75a03..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/payments/preferences/addmoney/PaymentsAddMoneyViewModel.java +++ /dev/null @@ -1,65 +0,0 @@ -package org.thoughtcrime.securesms.payments.preferences.addmoney; - -import android.net.Uri; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.lifecycle.LiveData; -import androidx.lifecycle.MutableLiveData; -import androidx.lifecycle.Transformations; -import androidx.lifecycle.ViewModel; -import androidx.lifecycle.ViewModelProvider; - -import org.thoughtcrime.securesms.util.AsynchronousCallback; -import org.signal.core.util.StringUtil; - -final class PaymentsAddMoneyViewModel extends ViewModel { - - private final MutableLiveData selfAddressAndUri = new MutableLiveData<>(); - private final MutableLiveData errors = new MutableLiveData<>(); - private final LiveData selfAddressUri; - private final LiveData selfAddressB58; - private final LiveData selfAddressAbbreviated; - - PaymentsAddMoneyViewModel(@NonNull PaymentsAddMoneyRepository paymentsAddMoneyRepository) { - paymentsAddMoneyRepository.getWalletAddress(new AsynchronousCallback.MainThread() { - @Override - public void onComplete(@Nullable AddressAndUri result) { - selfAddressAndUri.setValue(result); - } - - @Override - public void onError(@Nullable PaymentsAddMoneyRepository.Error error) { - errors.setValue(error); - } - }); - - selfAddressB58 = Transformations.map(selfAddressAndUri, AddressAndUri::getAddressB58); - selfAddressUri = Transformations.map(selfAddressAndUri, AddressAndUri::getUri); - selfAddressAbbreviated = Transformations.map(selfAddressB58, longAddress -> StringUtil.abbreviateInMiddle(longAddress, 17)); - } - - LiveData getSelfAddressB58() { - return selfAddressB58; - } - - LiveData getSelfAddressAbbreviated() { - return selfAddressAbbreviated; - } - - LiveData getErrors() { - return errors; - } - - LiveData getSelfAddressUriForQr() { - return selfAddressUri; - } - - public static final class Factory implements ViewModelProvider.Factory { - @Override - public @NonNull T create(@NonNull Class modelClass) { - //noinspection ConstantConditions - return modelClass.cast(new PaymentsAddMoneyViewModel(new PaymentsAddMoneyRepository())); - } - } -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/payments/preferences/addmoney/PaymentsAddMoneyViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/payments/preferences/addmoney/PaymentsAddMoneyViewModel.kt new file mode 100644 index 0000000000..8832aabdce --- /dev/null +++ b/app/src/main/java/org/thoughtcrime/securesms/payments/preferences/addmoney/PaymentsAddMoneyViewModel.kt @@ -0,0 +1,40 @@ +package org.thoughtcrime.securesms.payments.preferences.addmoney + +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel +import androidx.lifecycle.ViewModelProvider +import androidx.lifecycle.map +import io.reactivex.rxjava3.disposables.Disposable +import org.signal.core.util.Result +import org.signal.core.util.StringUtil + +internal class PaymentsAddMoneyViewModel(paymentsAddMoneyRepository: PaymentsAddMoneyRepository) : ViewModel() { + private val selfAddressAndUri = MutableLiveData() + private val walletDisposable: Disposable + + val errors = MutableLiveData() + val selfAddressB58: LiveData = selfAddressAndUri.map { it!!.addressB58 } + val selfAddressAbbreviated: LiveData = selfAddressB58.map { StringUtil.abbreviateInMiddle(it, 17) } + + init { + walletDisposable = paymentsAddMoneyRepository + .getWalletAddress() + .subscribe { result -> + when (result) { + is Result.Success -> selfAddressAndUri.postValue(result.success) + is Result.Failure -> errors.postValue(result.failure) + } + } + } + + override fun onCleared() { + walletDisposable.dispose() + } + + class Factory : ViewModelProvider.Factory { + override fun create(modelClass: Class): T { + return modelClass.cast(PaymentsAddMoneyViewModel(PaymentsAddMoneyRepository()))!! + } + } +} diff --git a/app/src/main/java/org/thoughtcrime/securesms/providers/BlobProvider.java b/app/src/main/java/org/thoughtcrime/securesms/providers/BlobProvider.java index c78b8a702c..9117af1015 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/providers/BlobProvider.java +++ b/app/src/main/java/org/thoughtcrime/securesms/providers/BlobProvider.java @@ -95,8 +95,33 @@ public class BlobProvider { return new BlobBuilder(data, fileSize); } + public synchronized boolean hasStream(@NonNull Context context, @NonNull Uri uri) { + waitUntilInitialized(); + try { + if (isAuthority(uri)) { + StorageType storageType = StorageType.decode(uri.getPathSegments().get(STORAGE_TYPE_PATH_SEGMENT)); + + if (storageType.isMemory()) { + byte[] data = memoryBlobs.get(uri); + + return data != null; + } else { + String id = uri.getPathSegments().get(ID_PATH_SEGMENT); + String directory = getDirectory(storageType); + File file = new File(getOrCreateDirectory(context, directory), buildFileName(id)); + + return file.exists(); + } + } + } catch (IOException e) { + // Intentionally left blank + } + return false; + } + /** * Retrieve a stream for the content with the specified URI. + * * @throws IOException If the stream fails to open or the spec of the URI doesn't match. */ public synchronized @NonNull InputStream getStream(@NonNull Context context, @NonNull Uri uri) throws IOException { @@ -106,6 +131,7 @@ public class BlobProvider { /** * Retrieve a stream for the content with the specified URI starting from the specified position. + * * @throws IOException If the stream fails to open or the spec of the URI doesn't match. */ public synchronized @NonNull InputStream getStream(@NonNull Context context, @NonNull Uri uri, long position) throws IOException { @@ -479,7 +505,7 @@ public class BlobProvider { * Create a blob that will exist for multiple app sessions. The file will be created on disk * synchronously, but the data will copied asynchronously. This is helpful when the copy is * long-running, such as in the case of recording a voice note. - * + *

* It is the caller's responsibility to eventually call {@link BlobProvider#delete(Context, Uri)} * when the blob is no longer in use. */