Update camera permission UI in media.

This commit is contained in:
mtang-signal
2024-05-13 10:45:00 -07:00
committed by Nicholas Tinsley
parent b14eddefc9
commit c3c743fbb8
15 changed files with 286 additions and 81 deletions

View File

@@ -131,14 +131,15 @@ public class DeviceActivity extends PassphraseRequiredActivity
Permissions.with(this)
.request(Manifest.permission.CAMERA)
.ifNecessary()
.withPermanentDenialDialog(getString(R.string.DeviceActivity_signal_needs_the_camera_permission_in_order_to_scan_a_qr_code))
.withRationaleDialog(getString(R.string.CameraXFragment_allow_access_camera), getString(R.string.CameraXFragment_to_scan_qr_code_allow_camera), R.drawable.symbol_camera_24)
.withPermanentDenialDialog(getString(R.string.DeviceActivity_signal_needs_the_camera_permission_in_order_to_scan_a_qr_code), null, R.string.CameraXFragment_allow_access_camera, R.string.CameraXFragment_to_scan_qr_codes, getSupportFragmentManager())
.onAllGranted(() -> {
getSupportFragmentManager().beginTransaction()
.replace(R.id.fragment_container, deviceAddFragment)
.addToBackStack(null)
.commitAllowingStateLoss();
})
.onAnyDenied(() -> Toast.makeText(this, R.string.DeviceActivity_unable_to_scan_a_qr_code_without_the_camera_permission, Toast.LENGTH_LONG).show())
.onAnyDenied(() -> Toast.makeText(this, R.string.CameraXFragment_signal_needs_camera_access_scan_qr_code, Toast.LENGTH_LONG).show())
.execute();
}

View File

@@ -30,6 +30,7 @@ import org.thoughtcrime.securesms.components.recyclerview.GridDividerDecoration
import org.thoughtcrime.securesms.groups.ParcelableGroupId
import org.thoughtcrime.securesms.mediasend.AvatarSelectionActivity
import org.thoughtcrime.securesms.mediasend.Media
import org.thoughtcrime.securesms.mediasend.camerax.CameraXUtil
import org.thoughtcrime.securesms.permissions.PermissionCompat
import org.thoughtcrime.securesms.permissions.Permissions
import org.thoughtcrime.securesms.util.ViewUtil
@@ -222,18 +223,22 @@ class AvatarPickerFragment : Fragment(R.layout.avatar_picker_fragment) {
@Suppress("DEPRECATION")
private fun openCameraCapture() {
Permissions.with(this)
.request(Manifest.permission.CAMERA)
.ifNecessary()
.onAllGranted {
val intent = AvatarSelectionActivity.getIntentForCameraCapture(requireContext())
startActivityForResult(intent, REQUEST_CODE_SELECT_IMAGE)
}
.onAnyDenied {
Toast.makeText(requireContext(), R.string.AvatarSelectionBottomSheetDialogFragment__taking_a_photo_requires_the_camera_permission, Toast.LENGTH_SHORT)
.show()
}
.execute()
if (CameraXUtil.isSupported()) {
val intent = AvatarSelectionActivity.getIntentForCameraCapture(requireContext())
startActivityForResult(intent, REQUEST_CODE_SELECT_IMAGE)
} else {
Permissions.with(this)
.request(Manifest.permission.CAMERA)
.ifNecessary()
.onAllGranted {
val intent = AvatarSelectionActivity.getIntentForCameraCapture(requireContext())
startActivityForResult(intent, REQUEST_CODE_SELECT_IMAGE)
}
.withRationaleDialog(getString(R.string.CameraXFragment_allow_access_camera), getString(R.string.CameraXFragment_to_capture_photos_allow_camera), R.drawable.symbol_camera_24)
.withPermanentDenialDialog(getString(R.string.AvatarSelectionBottomSheetDialogFragment__taking_a_photo_requires_the_camera_permission), null, R.string.CameraXFragment_allow_access_camera, R.string.CameraXFragment_to_capture_photos, getParentFragmentManager())
.onAnyDenied { Toast.makeText(requireContext(), R.string.AvatarSelectionBottomSheetDialogFragment__taking_a_photo_requires_the_camera_permission, Toast.LENGTH_SHORT).show() }
.execute()
}
}
@Suppress("DEPRECATION")

View File

@@ -78,6 +78,7 @@ import org.thoughtcrime.securesms.groups.ui.managegroup.dialogs.GroupInviteSentD
import org.thoughtcrime.securesms.groups.ui.managegroup.dialogs.GroupsLearnMoreBottomSheetDialogFragment
import org.thoughtcrime.securesms.mediaoverview.MediaOverviewActivity
import org.thoughtcrime.securesms.mediapreview.MediaIntentFactory
import org.thoughtcrime.securesms.mediasend.camerax.CameraXUtil
import org.thoughtcrime.securesms.messagerequests.MessageRequestRepository
import org.thoughtcrime.securesms.nicknames.NicknameActivity
import org.thoughtcrime.securesms.permissions.Permissions
@@ -420,14 +421,16 @@ class ConversationSettingsFragment : DSLSettingsFragment(
.setMessage(R.string.ConversationSettingsFragment__only_admins_of_this_group_can_add_to_its_story)
.setPositiveButton(android.R.string.ok) { d, _ -> d.dismiss() }
.show()
} else if (CameraXUtil.isSupported()) {
addToGroupStoryDelegate.addToStory(state.recipient.id)
} else {
Permissions.with(this@ConversationSettingsFragment)
.request(Manifest.permission.CAMERA)
.ifNecessary()
.withRationaleDialog(getString(R.string.ConversationActivity_to_capture_photos_and_video_allow_signal_access_to_the_camera), R.drawable.symbol_camera_24)
.withPermanentDenialDialog(getString(R.string.ConversationActivity_signal_needs_the_camera_permission_to_take_photos_or_video))
.withRationaleDialog(getString(R.string.CameraXFragment_allow_access_camera), getString(R.string.CameraXFragment_to_capture_photos_and_video_allow_camera), R.drawable.symbol_camera_24)
.withPermanentDenialDialog(getString(R.string.CameraXFragment_signal_needs_camera_access_capture_photos), null, R.string.CameraXFragment_allow_access_camera, R.string.CameraXFragment_to_capture_photos_videos, getParentFragmentManager())
.onAllGranted { addToGroupStoryDelegate.addToStory(state.recipient.id) }
.onAnyDenied { Toast.makeText(requireContext(), R.string.ConversationActivity_signal_needs_camera_permissions_to_take_photos_or_video, Toast.LENGTH_LONG).show() }
.onAnyDenied { Toast.makeText(requireContext(), R.string.CameraXFragment_signal_needs_camera_access_capture_photos, Toast.LENGTH_LONG).show() }
.execute()
}
},

View File

@@ -28,6 +28,7 @@ import org.thoughtcrime.securesms.giph.ui.GiphyActivity
import org.thoughtcrime.securesms.maps.PlacePickerActivity
import org.thoughtcrime.securesms.mediasend.Media
import org.thoughtcrime.securesms.mediasend.MediaSendActivityResult
import org.thoughtcrime.securesms.mediasend.camerax.CameraXUtil
import org.thoughtcrime.securesms.mediasend.v2.MediaSelectionActivity
import org.thoughtcrime.securesms.permissions.Permissions
import org.thoughtcrime.securesms.recipients.RecipientId
@@ -74,17 +75,22 @@ class ConversationActivityResultContracts(private val fragment: Fragment, privat
}
fun launchCamera(recipientId: RecipientId, isReply: Boolean) {
Permissions.with(fragment)
.request(Manifest.permission.CAMERA)
.ifNecessary()
.withRationaleDialog(fragment.getString(R.string.ConversationActivity_to_capture_photos_and_video_allow_signal_access_to_the_camera), R.drawable.symbol_camera_24)
.withPermanentDenialDialog(fragment.getString(R.string.ConversationActivity_signal_needs_the_camera_permission_to_take_photos_or_video))
.onAllGranted {
cameraLauncher.launch(MediaSelectionInput(emptyList(), recipientId, null, isReply))
fragment.requireActivity().overridePendingTransition(R.anim.camera_slide_from_bottom, R.anim.stationary)
}
.onAnyDenied { Toast.makeText(fragment.requireContext(), R.string.ConversationActivity_signal_needs_camera_permissions_to_take_photos_or_video, Toast.LENGTH_LONG).show() }
.execute()
if (CameraXUtil.isSupported()) {
cameraLauncher.launch(MediaSelectionInput(emptyList(), recipientId, null, isReply))
fragment.requireActivity().overridePendingTransition(R.anim.camera_slide_from_bottom, R.anim.stationary)
} else {
Permissions.with(fragment)
.request(Manifest.permission.CAMERA)
.ifNecessary()
.withRationaleDialog(fragment.getString(R.string.CameraXFragment_allow_access_camera), fragment.getString(R.string.CameraXFragment_to_capture_photos_and_video_allow_camera), R.drawable.symbol_camera_24)
.withPermanentDenialDialog(fragment.getString(R.string.CameraXFragment_signal_needs_camera_access_capture_photos), null, R.string.CameraXFragment_allow_access_camera, R.string.CameraXFragment_to_capture_photos_videos, fragment.parentFragmentManager)
.onAllGranted {
cameraLauncher.launch(MediaSelectionInput(emptyList(), recipientId, null, isReply))
fragment.requireActivity().overridePendingTransition(R.anim.camera_slide_from_bottom, R.anim.stationary)
}
.onAnyDenied { Toast.makeText(fragment.requireContext(), R.string.CameraXFragment_signal_needs_camera_access_capture_photos, Toast.LENGTH_LONG).show() }
.execute()
}
}
fun launchMediaEditor(mediaList: List<Media>, recipientId: RecipientId, text: CharSequence?) {

View File

@@ -144,6 +144,7 @@ import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.lock.v2.CreateSvrPinActivity;
import org.thoughtcrime.securesms.main.Material3OnScrollHelperBinder;
import org.thoughtcrime.securesms.main.SearchBinder;
import org.thoughtcrime.securesms.mediasend.camerax.CameraXUtil;
import org.thoughtcrime.securesms.mediasend.v2.MediaSelectionActivity;
import org.thoughtcrime.securesms.megaphone.Megaphone;
import org.thoughtcrime.securesms.megaphone.MegaphoneActionController;
@@ -392,14 +393,18 @@ public class ConversationListFragment extends MainFragment implements ActionMode
fab.setOnClickListener(v -> startActivity(new Intent(getActivity(), NewConversationActivity.class)));
cameraFab.setOnClickListener(v -> {
Permissions.with(this)
.request(Manifest.permission.CAMERA)
.ifNecessary()
.withRationaleDialog(getString(R.string.ConversationActivity_to_capture_photos_and_video_allow_signal_access_to_the_camera), R.drawable.symbol_camera_24)
.withPermanentDenialDialog(getString(R.string.ConversationActivity_signal_needs_the_camera_permission_to_take_photos_or_video))
.onAllGranted(() -> startActivity(MediaSelectionActivity.camera(requireContext())))
.onAnyDenied(() -> Toast.makeText(requireContext(), R.string.ConversationActivity_signal_needs_camera_permissions_to_take_photos_or_video, Toast.LENGTH_LONG).show())
.execute();
if (CameraXUtil.isSupported()) {
startActivity(MediaSelectionActivity.camera(requireContext()));
} else {
Permissions.with(this)
.request(Manifest.permission.CAMERA)
.ifNecessary()
.withRationaleDialog(getString(R.string.CameraXFragment_allow_access_camera), getString(R.string.CameraXFragment_to_capture_photos_and_video_allow_camera), R.drawable.symbol_camera_24)
.withPermanentDenialDialog(getString(R.string.CameraXFragment_signal_needs_camera_access_capture_photos), null, R.string.CameraXFragment_allow_access_camera, R.string.CameraXFragment_to_capture_photos_videos, getParentFragmentManager())
.onAllGranted(() -> startActivity(MediaSelectionActivity.camera(requireContext())))
.onAnyDenied(() -> Toast.makeText(requireContext(), R.string.CameraXFragment_signal_needs_camera_access_capture_photos, Toast.LENGTH_LONG).show())
.execute();
}
});
initializeViewModel();

View File

@@ -1,11 +1,11 @@
package org.thoughtcrime.securesms.mediasend;
import android.Manifest;
import android.animation.Animator;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Color;
import android.os.Build;
@@ -24,6 +24,8 @@ import android.view.animation.AnimationUtils;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.RotateAnimation;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -37,6 +39,7 @@ import androidx.constraintlayout.widget.ConstraintSet;
import androidx.core.content.ContextCompat;
import com.bumptech.glide.Glide;
import com.google.android.material.button.MaterialButton;
import com.google.android.material.card.MaterialCardView;
import org.signal.core.util.Stopwatch;
@@ -57,6 +60,8 @@ import org.thoughtcrime.securesms.mediasend.v2.MediaAnimations;
import org.thoughtcrime.securesms.mediasend.v2.MediaCountIndicatorButton;
import org.thoughtcrime.securesms.mms.DecryptableStreamUriLoader.DecryptableUri;
import org.thoughtcrime.securesms.mms.MediaConstraints;
import org.thoughtcrime.securesms.permissions.Permissions;
import org.thoughtcrime.securesms.util.BottomSheetUtil;
import org.thoughtcrime.securesms.util.FeatureFlags;
import org.thoughtcrime.securesms.util.MemoryFileDescriptor;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
@@ -65,6 +70,7 @@ import org.thoughtcrime.securesms.video.VideoUtil;
import java.io.FileDescriptor;
import java.io.IOException;
import java.util.List;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
@@ -72,6 +78,8 @@ import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
import io.reactivex.rxjava3.disposables.Disposable;
import kotlin.Unit;
import static org.thoughtcrime.securesms.permissions.PermissionDeniedBottomSheet.showPermissionFragment;
/**
* Camera captured implemented using the CameraX SDK, which uses Camera2 under the hood. Should be
* preferred whenever possible.
@@ -98,6 +106,9 @@ public class CameraXFragment extends LoggingFragment implements CameraFragment {
private CameraXModePolicy cameraXModePolicy;
private CameraScreenBrightnessController cameraScreenBrightnessController;
private boolean isMediaSelected;
private View missingPermissionsContainer;
private TextView missingPermissionsText;
private MaterialButton allowAccessButton;
private final Executor qrAnalysisExecutor = Executors.newSingleThreadExecutor();
private final QrProcessor qrProcessor = new QrProcessor();
@@ -149,13 +160,18 @@ public class CameraXFragment extends LoggingFragment implements CameraFragment {
@SuppressLint("MissingPermission")
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
this.cameraParent = view.findViewById(R.id.camerax_camera_parent);
this.cameraParent = view.findViewById(R.id.camerax_camera_parent);
this.previewView = view.findViewById(R.id.camerax_camera);
this.controlsContainer = view.findViewById(R.id.camerax_controls_container);
this.cameraXModePolicy = CameraXModePolicy.acquire(requireContext(),
controller.getMediaConstraints(),
requireArguments().getBoolean(IS_VIDEO_ENABLED, true));
this.previewView = view.findViewById(R.id.camerax_camera);
this.controlsContainer = view.findViewById(R.id.camerax_controls_container);
this.cameraXModePolicy = CameraXModePolicy.acquire(requireContext(),
controller.getMediaConstraints(),
requireArguments().getBoolean(IS_VIDEO_ENABLED, true));
this.missingPermissionsContainer = view.findViewById(R.id.missing_permissions_container);
this.missingPermissionsText = view.findViewById(R.id.missing_permissions_text);
this.allowAccessButton = view.findViewById(R.id.allow_access_button);
checkPermissions(requireArguments().getBoolean(IS_VIDEO_ENABLED, true));
Log.d(TAG, "Starting CameraX with mode policy " + cameraXModePolicy.getClass().getSimpleName());
@@ -218,6 +234,9 @@ public class CameraXFragment extends LoggingFragment implements CameraFragment {
cameraController.bindToLifecycle(getViewLifecycleOwner(), () -> Log.d(TAG, "Camera init complete from onResume"));
requireActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
if (hasCameraPermission()) {
missingPermissionsContainer.setVisibility(View.GONE);
}
}
@Override
@@ -259,6 +278,61 @@ public class CameraXFragment extends LoggingFragment implements CameraFragment {
});
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
Permissions.onRequestPermissionsResult(this, requestCode, permissions, grantResults);
}
private void checkPermissions(boolean includeAudio) {
if (hasCameraPermission()) {
missingPermissionsContainer.setVisibility(View.GONE);
} else {
boolean hasAudioPermission = Permissions.hasAll(requireContext(), Manifest.permission.RECORD_AUDIO);
missingPermissionsContainer.setVisibility(View.VISIBLE);
int textResId = (!includeAudio || hasAudioPermission) ? R.string.CameraXFragment_to_capture_photos_and_video_allow_camera : R.string.CameraXFragment_to_capture_photos_and_video_allow_camera_microphone;
missingPermissionsText.setText(textResId);
allowAccessButton.setOnClickListener(v -> requestPermissions(includeAudio));
}
}
private void requestPermissions(boolean includeAudio) {
if (includeAudio) {
Permissions.with(this)
.request(Manifest.permission.CAMERA, Manifest.permission.RECORD_AUDIO)
.ifNecessary()
.onSomeGranted(permissions -> {
if (permissions.contains(Manifest.permission.CAMERA)) {
missingPermissionsContainer.setVisibility(View.GONE);
}
})
.onSomePermanentlyDenied(deniedPermissions -> {
if (deniedPermissions.containsAll(List.of(Manifest.permission.CAMERA, Manifest.permission.RECORD_AUDIO))) {
showPermissionFragment(R.string.CameraXFragment_allow_access_camera_microphone, R.string.CameraXFragment_to_capture_photos_videos).show(getParentFragmentManager(), BottomSheetUtil.STANDARD_BOTTOM_SHEET_FRAGMENT_TAG);
} else if (deniedPermissions.contains(Manifest.permission.CAMERA)) {
showPermissionFragment(R.string.CameraXFragment_allow_access_camera, R.string.CameraXFragment_to_capture_photos_videos).show(getParentFragmentManager(), BottomSheetUtil.STANDARD_BOTTOM_SHEET_FRAGMENT_TAG);
}
})
.onSomeDenied(deniedPermissions -> {
if (deniedPermissions.contains(Manifest.permission.CAMERA)) {
Toast.makeText(requireContext(), R.string.CameraXFragment_signal_needs_camera_access_capture_photos, Toast.LENGTH_LONG).show();
}
})
.execute();
} else {
Permissions.with(this)
.request(Manifest.permission.CAMERA)
.ifNecessary()
.onAllGranted (() -> missingPermissionsContainer.setVisibility(View.GONE))
.onAnyDenied(() -> Toast.makeText(requireContext(), R.string.CameraXFragment_signal_needs_camera_access_capture_photos, Toast.LENGTH_LONG).show())
.withPermanentDenialDialog(getString(R.string.CameraXFragment_signal_needs_camera_access_capture_photos), null, R.string.CameraXFragment_allow_access_camera, R.string.CameraXFragment_to_capture_photos, getParentFragmentManager())
.execute();
}
}
private boolean hasCameraPermission() {
return Permissions.hasAll(requireContext(), Manifest.permission.CAMERA);
}
private void onOrientationChanged() {
int layout = R.layout.camera_controls_portrait;
@@ -356,7 +430,7 @@ public class CameraXFragment extends LoggingFragment implements CameraFragment {
selfieFlash = requireView().findViewById(R.id.camera_selfie_flash);
captureButton.setOnClickListener(v -> {
if (cameraController.isInitialized()) {
if (hasCameraPermission() && cameraController.isInitialized()) {
captureButton.setEnabled(false);
flipButton.setEnabled(false);
flashButton.setEnabled(false);

View File

@@ -118,13 +118,17 @@ class CameraXVideoCaptureHelper implements CameraButtonView.VideoCaptureListener
public void onVideoCaptureStarted() {
Log.d(TAG, "onVideoCaptureStarted");
if (canRecordAudio()) {
if (canUseCamera() && canRecordAudio()) {
beginCameraRecording();
} else {
} else if (!canRecordAudio()) {
displayAudioRecordingPermissionsDialog();
}
}
private boolean canUseCamera() {
return Permissions.hasAll(fragment.requireContext(), Manifest.permission.CAMERA);
}
private boolean canRecordAudio() {
return Permissions.hasAll(fragment.requireContext(), Manifest.permission.RECORD_AUDIO);
}
@@ -133,9 +137,9 @@ class CameraXVideoCaptureHelper implements CameraButtonView.VideoCaptureListener
Permissions.with(fragment)
.request(Manifest.permission.RECORD_AUDIO)
.ifNecessary()
.withRationaleDialog(fragment.getString(R.string.ConversationActivity_enable_the_microphone_permission_to_capture_videos_with_sound), R.drawable.ic_mic_solid_24)
.withPermanentDenialDialog(fragment.getString(R.string.ConversationActivity_signal_needs_the_recording_permissions_to_capture_video))
.onAnyDenied(() -> Toast.makeText(fragment.requireContext(), R.string.ConversationActivity_signal_needs_recording_permissions_to_capture_video, Toast.LENGTH_LONG).show())
.withRationaleDialog(fragment.getString(R.string.CameraXFragment_allow_access_microphone), fragment.getString(R.string.CameraXFragment_to_capture_videos_with_sound), R.drawable.ic_mic_24)
.withPermanentDenialDialog(fragment.getString(R.string.ConversationActivity_signal_needs_the_recording_permissions_to_capture_video), null, R.string.CameraXFragment_allow_access_microphone, R.string.CameraXFragment_to_capture_videos, fragment.getParentFragmentManager())
.onAnyDenied(() -> Toast.makeText(fragment.requireContext(), R.string.CameraXFragment_signal_needs_microphone_access_video, Toast.LENGTH_LONG).show())
.execute();
}

View File

@@ -5,6 +5,7 @@ import android.widget.Toast
import androidx.fragment.app.Fragment
import androidx.navigation.NavController
import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.mediasend.camerax.CameraXUtil
import org.thoughtcrime.securesms.permissions.PermissionCompat
import org.thoughtcrime.securesms.permissions.Permissions
import org.thoughtcrime.securesms.util.navigation.safeNavigate
@@ -33,14 +34,18 @@ class MediaSelectionNavigator(
fun Fragment.requestPermissionsForCamera(
onGranted: () -> Unit
) {
Permissions.with(this)
.request(Manifest.permission.CAMERA)
.ifNecessary()
.withRationaleDialog(getString(R.string.ConversationActivity_to_capture_photos_and_video_allow_signal_access_to_the_camera), R.drawable.ic_camera_24)
.withPermanentDenialDialog(getString(R.string.ConversationActivity_signal_needs_the_camera_permission_to_take_photos_or_video))
.onAllGranted(onGranted)
.onAnyDenied { Toast.makeText(requireContext(), R.string.ConversationActivity_signal_needs_camera_permissions_to_take_photos_or_video, Toast.LENGTH_LONG).show() }
.execute()
if (CameraXUtil.isSupported()) {
onGranted()
} else {
Permissions.with(this)
.request(Manifest.permission.CAMERA)
.ifNecessary()
.withRationaleDialog(getString(R.string.CameraXFragment_allow_access_camera), getString(R.string.CameraXFragment_to_capture_photos_and_video_allow_camera), R.drawable.ic_camera_24)
.withPermanentDenialDialog(getString(R.string.CameraXFragment_signal_needs_camera_access_capture_photos), null, R.string.CameraXFragment_allow_access_camera, R.string.CameraXFragment_to_capture_photos_videos, getParentFragmentManager())
.onAllGranted(onGranted)
.onAnyDenied { Toast.makeText(requireContext(), R.string.CameraXFragment_signal_needs_camera_access_capture_photos, Toast.LENGTH_LONG).show() }
.execute()
}
}
fun Fragment.requestPermissionsForGallery(

View File

@@ -1,5 +1,6 @@
package org.thoughtcrime.securesms.mediasend.v2.gallery
import android.Manifest
import android.os.Bundle
import android.view.View
import android.widget.Toast
@@ -19,6 +20,7 @@ import org.thoughtcrime.securesms.components.recyclerview.GridDividerDecoration
import org.thoughtcrime.securesms.databinding.V2MediaGalleryFragmentBinding
import org.thoughtcrime.securesms.mediasend.Media
import org.thoughtcrime.securesms.mediasend.MediaRepository
import org.thoughtcrime.securesms.mediasend.camerax.CameraXUtil
import org.thoughtcrime.securesms.permissions.PermissionCompat
import org.thoughtcrime.securesms.permissions.Permissions
import org.thoughtcrime.securesms.util.Material3OnScrollHelper
@@ -94,7 +96,18 @@ class MediaGalleryFragment : Fragment(R.layout.v2_media_gallery_fragment) {
if (callbacks.isCameraEnabled()) {
binding.mediaGalleryToolbar.setOnMenuItemClickListener { item ->
if (item.itemId == R.id.action_camera) {
callbacks.onNavigateToCamera()
if (CameraXUtil.isSupported()) {
callbacks.onNavigateToCamera()
} else {
Permissions.with(this)
.request(Manifest.permission.CAMERA)
.ifNecessary()
.onAllGranted { callbacks.onNavigateToCamera() }
.withRationaleDialog(getString(R.string.CameraXFragment_allow_access_camera), getString(R.string.CameraXFragment_to_capture_photos_and_video_allow_camera), R.drawable.ic_camera_24)
.withPermanentDenialDialog(getString(R.string.CameraXFragment_signal_needs_camera_access_capture_photos), null, R.string.CameraXFragment_allow_access_camera, R.string.CameraXFragment_to_capture_photos_videos, getParentFragmentManager())
.onAnyDenied { Toast.makeText(requireContext(), R.string.CameraXFragment_signal_needs_camera_access_capture_photos, Toast.LENGTH_LONG).show() }
.execute()
}
true
} else {
false

View File

@@ -96,22 +96,13 @@ public final class PaymentsTransferFragment extends LoggingFragment {
Permissions.with(this)
.request(Manifest.permission.CAMERA)
.ifNecessary()
.withRationaleDialog(getString(R.string.PaymentsTransferFragment__to_scan_a_qr_code_signal_needs), R.drawable.ic_camera_24)
.onAnyPermanentlyDenied(this::onCameraPermissionPermanentlyDenied)
.withRationaleDialog(getString(R.string.CameraXFragment_allow_access_camera), getString(R.string.PaymentsTransferFragment__to_scan_a_qr_code_signal_needs), R.drawable.ic_camera_24)
.withPermanentDenialDialog(getString(R.string.PaymentsTransferFragment__to_scan_a_qr_code_signal_needs_access_to_the_camera), null, R.string.CameraXFragment_allow_access_camera, R.string.CameraXFragment_to_scan_qr_codes, getParentFragmentManager())
.onAllGranted(() -> SafeNavigation.safeNavigate(Navigation.findNavController(requireView()), R.id.action_paymentsTransfer_to_paymentsScanQr))
.onAnyDenied(() -> Toast.makeText(requireContext(), R.string.PaymentsTransferFragment__to_scan_a_qr_code_signal_needs_access_to_the_camera, Toast.LENGTH_LONG).show())
.execute();
}
private void onCameraPermissionPermanentlyDenied() {
new MaterialAlertDialogBuilder(requireContext())
.setTitle(R.string.Permissions_permission_required)
.setMessage(R.string.PaymentsTransferFragment__signal_needs_the_camera_permission_to_capture_qr_code_go_to_settings)
.setPositiveButton(R.string.PaymentsTransferFragment__settings, (dialog, which) -> requireActivity().startActivity(Permissions.getApplicationSettingsIntent(requireContext())))
.setNegativeButton(android.R.string.cancel, null)
.show();
}
@Override
@SuppressWarnings("deprecation")
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {

View File

@@ -47,6 +47,7 @@ import org.thoughtcrime.securesms.dependencies.ApplicationDependencies
import org.thoughtcrime.securesms.events.ReminderUpdateEvent
import org.thoughtcrime.securesms.main.Material3OnScrollHelperBinder
import org.thoughtcrime.securesms.main.SearchBinder
import org.thoughtcrime.securesms.mediasend.camerax.CameraXUtil
import org.thoughtcrime.securesms.mediasend.v2.MediaSelectionActivity
import org.thoughtcrime.securesms.permissions.Permissions
import org.thoughtcrime.securesms.registration.RegistrationNavigationActivity
@@ -224,16 +225,18 @@ class StoriesLandingFragment : DSLSettingsFragment(layoutId = R.layout.stories_l
})
cameraFab.setOnClickListener {
Permissions.with(this)
.request(Manifest.permission.CAMERA)
.ifNecessary()
.withRationaleDialog(getString(R.string.ConversationActivity_to_capture_photos_and_video_allow_signal_access_to_the_camera), R.drawable.symbol_camera_24)
.withPermanentDenialDialog(getString(R.string.ConversationActivity_signal_needs_the_camera_permission_to_take_photos_or_video))
.onAllGranted {
startActivityIfAble(MediaSelectionActivity.camera(requireContext(), isStory = true))
}
.onAnyDenied { Toast.makeText(requireContext(), R.string.ConversationActivity_signal_needs_camera_permissions_to_take_photos_or_video, Toast.LENGTH_LONG).show() }
.execute()
if (CameraXUtil.isSupported()) {
startActivityIfAble(MediaSelectionActivity.camera(requireContext(), isStory = true))
} else {
Permissions.with(this)
.request(Manifest.permission.CAMERA)
.ifNecessary()
.onAllGranted { startActivityIfAble(MediaSelectionActivity.camera(requireContext(), isStory = true)) }
.withRationaleDialog(getString(R.string.CameraXFragment_allow_access_camera), getString(R.string.CameraXFragment_to_capture_photos_and_video_allow_camera), R.drawable.symbol_camera_24)
.withPermanentDenialDialog(getString(R.string.CameraXFragment_signal_needs_camera_access_capture_photos), null, R.string.CameraXFragment_allow_access_camera, R.string.CameraXFragment_to_capture_photos_videos, getParentFragmentManager())
.onAnyDenied { Toast.makeText(requireContext(), R.string.CameraXFragment_signal_needs_camera_access_capture_photos, Toast.LENGTH_LONG).show() }
.execute()
}
}
viewModel.state.observe(viewLifecycleOwner) {

View File

@@ -106,7 +106,8 @@ class VerifyIdentityFragment : Fragment(R.layout.fragment_container), ScanListen
Permissions.with(this)
.request(Manifest.permission.CAMERA)
.ifNecessary()
.withPermanentDenialDialog(getString(R.string.VerifyIdentityActivity_signal_needs_the_camera_permission_in_order_to_scan_a_qr_code_but_it_has_been_permanently_denied))
.withRationaleDialog(getString(R.string.CameraXFragment_allow_access_camera), getString(R.string.CameraXFragment_to_scan_qr_code_allow_camera), R.drawable.ic_camera_24)
.withPermanentDenialDialog(getString(R.string.VerifyIdentityActivity_signal_needs_the_camera_permission_in_order_to_scan_a_qr_code_but_it_has_been_permanently_denied), null, R.string.CameraXFragment_allow_access_camera, R.string.CameraXFragment_to_scan_qr_codes, getParentFragmentManager())
.onAllGranted {
childFragmentManager.beginTransaction()
.setCustomAnimations(R.anim.slide_from_top, R.anim.slide_to_bottom, R.anim.slide_from_bottom, R.anim.slide_to_top)
@@ -114,7 +115,7 @@ class VerifyIdentityFragment : Fragment(R.layout.fragment_container), ScanListen
.addToBackStack(null)
.commitAllowingStateLoss()
}
.onAnyDenied { Toast.makeText(requireContext(), R.string.VerifyIdentityActivity_unable_to_scan_qr_code_without_camera_permission, Toast.LENGTH_LONG).show() }
.onAnyDenied { Toast.makeText(requireContext(), R.string.CameraXFragment_signal_needs_camera_access_scan_qr_code, Toast.LENGTH_LONG).show() }
.execute()
}