Fix crashes related to activity starts.

This commit is contained in:
Cody Henthorne
2023-09-18 15:33:24 -04:00
committed by Alex Hart
parent efbd5cab85
commit 835fd47482
6 changed files with 100 additions and 102 deletions

View File

@@ -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<Bundle> = if (editorCount > 0 && blobUri != null) {
val accumulator: MutableList<Bundle> = mutableListOf<Bundle>()
val blobProvider: BlobProvider = BlobProvider.getInstance()
val blobProvider: BlobProvider = BlobProvider.getInstance()
val editorStates: List<Bundle> = if (editorCount > 0 && blobUri != null && blobProvider.hasStream(context, blobUri)) {
val accumulator: MutableList<Bundle> = mutableListOf()
val blob: ByteArray = ByteStreams.toByteArray(blobProvider.getStream(context, blobUri))
val parcel: Parcel = Parcel.obtain()
parcel.unmarshall(blob, 0, blob.size)

View File

@@ -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<AddressAndUri, Error> 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
}
}

View File

@@ -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<SignalResult<AddressAndUri, Error>> {
if (!SignalStore.paymentsValues().mobileCoinPaymentsEnabled()) {
return Single.just(SignalResult.failure(Error.PAYMENTS_NOT_ENABLED))
}
return Single.fromCallable<SignalResult<AddressAndUri, Error>> {
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
}
}

View File

@@ -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<AddressAndUri> selfAddressAndUri = new MutableLiveData<>();
private final MutableLiveData<PaymentsAddMoneyRepository.Error> errors = new MutableLiveData<>();
private final LiveData<Uri> selfAddressUri;
private final LiveData<String> selfAddressB58;
private final LiveData<CharSequence> selfAddressAbbreviated;
PaymentsAddMoneyViewModel(@NonNull PaymentsAddMoneyRepository paymentsAddMoneyRepository) {
paymentsAddMoneyRepository.getWalletAddress(new AsynchronousCallback.MainThread<AddressAndUri, PaymentsAddMoneyRepository.Error>() {
@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<String> getSelfAddressB58() {
return selfAddressB58;
}
LiveData<CharSequence> getSelfAddressAbbreviated() {
return selfAddressAbbreviated;
}
LiveData<PaymentsAddMoneyRepository.Error> getErrors() {
return errors;
}
LiveData<Uri> getSelfAddressUriForQr() {
return selfAddressUri;
}
public static final class Factory implements ViewModelProvider.Factory {
@Override
public @NonNull <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
//noinspection ConstantConditions
return modelClass.cast(new PaymentsAddMoneyViewModel(new PaymentsAddMoneyRepository()));
}
}
}

View File

@@ -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<AddressAndUri>()
private val walletDisposable: Disposable
val errors = MutableLiveData<PaymentsAddMoneyRepository.Error>()
val selfAddressB58: LiveData<String> = selfAddressAndUri.map { it!!.addressB58 }
val selfAddressAbbreviated: LiveData<CharSequence?> = 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 <T : ViewModel> create(modelClass: Class<T>): T {
return modelClass.cast(PaymentsAddMoneyViewModel(PaymentsAddMoneyRepository()))!!
}
}
}

View File

@@ -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.
*
* <p>
* It is the caller's responsibility to eventually call {@link BlobProvider#delete(Context, Uri)}
* when the blob is no longer in use.
*/