mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-02-15 07:28:30 +00:00
Fix crashes related to activity starts.
This commit is contained in:
committed by
Alex Hart
parent
efbd5cab85
commit
835fd47482
@@ -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)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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()))!!
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user