diff --git a/src/org/thoughtcrime/securesms/avatar/AvatarSelection.java b/src/org/thoughtcrime/securesms/avatar/AvatarSelection.java index 5f1e26fc6f..4a4f65883e 100644 --- a/src/org/thoughtcrime/securesms/avatar/AvatarSelection.java +++ b/src/org/thoughtcrime/securesms/avatar/AvatarSelection.java @@ -4,23 +4,20 @@ import android.Manifest; import android.app.Activity; import android.content.Context; import android.content.Intent; +import android.content.pm.PackageManager; import android.net.Uri; import android.os.Build; -import android.os.Environment; import android.provider.MediaStore; + import androidx.annotation.Nullable; import androidx.annotation.StringRes; -import androidx.core.app.ShareCompat; import androidx.core.content.ContextCompat; import com.theartofdev.edmodo.cropper.CropImage; import com.theartofdev.edmodo.cropper.CropImageView; -import network.loki.messenger.R; - import org.thoughtcrime.securesms.database.NoExternalStorageException; import org.thoughtcrime.securesms.logging.Log; -import org.thoughtcrime.securesms.permissions.Permissions; import org.thoughtcrime.securesms.util.ExternalStorageUtil; import org.thoughtcrime.securesms.util.FileProviderUtil; import org.thoughtcrime.securesms.util.IntentUtils; @@ -30,6 +27,8 @@ import java.io.IOException; import java.util.LinkedList; import java.util.List; +import network.loki.messenger.R; + import static android.provider.MediaStore.EXTRA_OUTPUT; public final class AvatarSelection { @@ -69,7 +68,9 @@ public final class AvatarSelection { */ public static File startAvatarSelection(Activity activity, boolean includeClear, boolean attemptToIncludeCamera) { File captureFile = null; - if (attemptToIncludeCamera) { + boolean hasCameraPermission = ContextCompat + .checkSelfPermission(activity, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED; + if (attemptToIncludeCamera && hasCameraPermission) { try { captureFile = File.createTempFile("avatar-capture", ".jpg", ExternalStorageUtil.getImageDir(activity)); } catch (IOException | NoExternalStorageException e) { @@ -84,7 +85,7 @@ public final class AvatarSelection { private static Intent createAvatarSelectionIntent(Context context, @Nullable File tempCaptureFile, boolean includeClear) { List extraIntents = new LinkedList<>(); - Intent galleryIntent = new Intent(Intent.ACTION_PICK); + Intent galleryIntent = new Intent(Intent.ACTION_PICK); galleryIntent.setDataAndType(android.provider.MediaStore.Images.Media.INTERNAL_CONTENT_URI, "image/*"); if (!IntentUtils.isResolvable(context, galleryIntent)) { diff --git a/src/org/thoughtcrime/securesms/loki/activities/SettingsActivity.kt b/src/org/thoughtcrime/securesms/loki/activities/SettingsActivity.kt index 1a88113784..45092b0c06 100644 --- a/src/org/thoughtcrime/securesms/loki/activities/SettingsActivity.kt +++ b/src/org/thoughtcrime/securesms/loki/activities/SettingsActivity.kt @@ -1,5 +1,6 @@ package org.thoughtcrime.securesms.loki.activities +import android.Manifest import android.app.Activity import android.content.ClipData import android.content.ClipboardManager @@ -38,6 +39,7 @@ import org.thoughtcrime.securesms.loki.utilities.fadeOut import org.thoughtcrime.securesms.loki.utilities.push import org.thoughtcrime.securesms.mms.GlideApp import org.thoughtcrime.securesms.mms.GlideRequests +import org.thoughtcrime.securesms.permissions.Permissions import org.thoughtcrime.securesms.profiles.AvatarHelper import org.thoughtcrime.securesms.profiles.ProfileMediaConstraints import org.thoughtcrime.securesms.util.BitmapDecodingException @@ -153,6 +155,11 @@ class SettingsActivity : PassphraseRequiredActionBarActivity() { } } } + + override fun onRequestPermissionsResult(requestCode: Int, permissions: Array, grantResults: IntArray) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults) + Permissions.onRequestPermissionsResult(this, requestCode, permissions, grantResults) + } // endregion // region Updating @@ -246,7 +253,13 @@ class SettingsActivity : PassphraseRequiredActionBarActivity() { } private fun showEditProfilePictureUI() { - tempFile = AvatarSelection.startAvatarSelection(this, false, true) + // Ask for an optional camera permission. + Permissions.with(this) + .request(Manifest.permission.CAMERA) + .onAnyResult { + tempFile = AvatarSelection.startAvatarSelection(this, false, true) + } + .execute() } private fun copyPublicKey() { diff --git a/src/org/thoughtcrime/securesms/mms/AttachmentManager.java b/src/org/thoughtcrime/securesms/mms/AttachmentManager.java index 5f13c13e6c..53e4ca54cc 100644 --- a/src/org/thoughtcrime/securesms/mms/AttachmentManager.java +++ b/src/org/thoughtcrime/securesms/mms/AttachmentManager.java @@ -46,6 +46,7 @@ import org.thoughtcrime.securesms.components.RemovableEditableMediaView; import org.thoughtcrime.securesms.components.ThumbnailView; import org.thoughtcrime.securesms.components.location.SignalMapView; import org.thoughtcrime.securesms.components.location.SignalPlace; +import org.thoughtcrime.securesms.database.NoExternalStorageException; import org.thoughtcrime.securesms.giph.ui.GiphyActivity; import org.thoughtcrime.securesms.logging.Log; import org.thoughtcrime.securesms.mediasend.MediaSendActivity; @@ -54,6 +55,8 @@ import org.thoughtcrime.securesms.providers.BlobProvider; import org.thoughtcrime.securesms.providers.DeprecatedPersistentBlobProvider; import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.util.BitmapUtil; +import org.thoughtcrime.securesms.util.ExternalStorageUtil; +import org.thoughtcrime.securesms.util.FileProviderUtil; import org.thoughtcrime.securesms.util.MediaUtil; import org.thoughtcrime.securesms.util.ThemeUtil; import org.thoughtcrime.securesms.util.Util; @@ -65,6 +68,7 @@ import org.thoughtcrime.securesms.util.concurrent.SettableFuture; import org.thoughtcrime.securesms.util.views.Stub; import org.whispersystems.libsignal.util.guava.Optional; +import java.io.File; import java.io.IOException; import java.util.Iterator; import java.util.LinkedList; @@ -73,6 +77,8 @@ import java.util.concurrent.ExecutionException; import network.loki.messenger.R; +import static android.provider.MediaStore.EXTRA_OUTPUT; + public class AttachmentManager { @@ -112,7 +118,6 @@ public class AttachmentManager { thumbnail.setOnClickListener(new ThumbnailClickListener()); documentView.getBackground().setColorFilter(ThemeUtil.getThemedColor(context, R.attr.conversation_item_bubble_background), PorterDuff.Mode.MULTIPLY); } - } public void clear(@NonNull GlideRequests glideRequests, boolean animate) { @@ -438,25 +443,29 @@ public class AttachmentManager { public void capturePhoto(Activity activity, int requestCode) { Permissions.with(activity) - .request(Manifest.permission.CAMERA) - .ifNecessary() - .withPermanentDenialDialog(activity.getString(R.string.AttachmentManager_signal_requires_the_camera_permission_in_order_to_take_photos_but_it_has_been_permanently_denied)) - .onAllGranted(() -> { - try { - Intent captureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); - if (captureIntent.resolveActivity(activity.getPackageManager()) != null) { - if (captureUri == null) { - captureUri = DeprecatedPersistentBlobProvider.getInstance(context).createForExternal(context, MediaUtil.IMAGE_JPEG); - } - Log.d(TAG, "captureUri path is " + captureUri.getPath()); - captureIntent.putExtra(MediaStore.EXTRA_OUTPUT, captureUri); - activity.startActivityForResult(captureIntent, requestCode); - } - } catch (IOException ioe) { - Log.w(TAG, ioe); - } - }) - .execute(); + .request(Manifest.permission.CAMERA) + .ifNecessary() + .withPermanentDenialDialog(activity.getString(R.string.AttachmentManager_signal_requires_the_camera_permission_in_order_to_take_photos_but_it_has_been_permanently_denied)) + .onAllGranted(() -> { + try { + File captureFile = File.createTempFile( + "conversation-capture", + ".jpg", + ExternalStorageUtil.getImageDir(activity)); + Uri captureUri = FileProviderUtil.getUriFor(context, captureFile); + Intent captureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); + captureIntent.putExtra(EXTRA_OUTPUT, captureUri); + captureIntent.setFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION); + if (captureIntent.resolveActivity(activity.getPackageManager()) != null) { + Log.d(TAG, "captureUri path is " + captureUri.getPath()); + this.captureUri = captureUri; + activity.startActivityForResult(captureIntent, requestCode); + } + } catch (IOException | NoExternalStorageException e) { + throw new RuntimeException("Error creating image capture intent.", e); + } + }) + .execute(); } private static void selectMediaType(Activity activity, @NonNull String type, @Nullable String[] extraMimeType, int requestCode) { diff --git a/src/org/thoughtcrime/securesms/permissions/Permissions.java b/src/org/thoughtcrime/securesms/permissions/Permissions.java index 70e2da80fb..f647da6db4 100644 --- a/src/org/thoughtcrime/securesms/permissions/Permissions.java +++ b/src/org/thoughtcrime/securesms/permissions/Permissions.java @@ -171,7 +171,7 @@ public class Permissions { } for (String permission : requestedPermissions) { - request.addMapping(permission, permissionObject.shouldShouldPermissionRationale(permission)); + request.addMapping(permission, permissionObject.shouldShowPermissionRationale(permission)); } permissionObject.requestPermissions(requestCode, requestedPermissions); @@ -240,7 +240,7 @@ public class Permissions { for (int i=0;i