diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityResultContracts.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityResultContracts.kt index 8c95352892..1b3c845b00 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityResultContracts.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityResultContracts.kt @@ -16,7 +16,6 @@ import android.widget.Toast import androidx.activity.result.contract.ActivityResultContract import androidx.core.content.IntentCompat import androidx.fragment.app.Fragment -import com.google.android.material.dialog.MaterialAlertDialogBuilder import org.signal.core.util.logging.Log import org.thoughtcrime.securesms.R import org.thoughtcrime.securesms.components.location.SignalPlace @@ -107,23 +106,14 @@ class ConversationActivityResultContracts(private val fragment: Fragment, privat if (Permissions.hasAny(fragment.requireContext(), Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION)) { selectLocationLauncher.launch(chatColors) } else { - val dialog = MaterialAlertDialogBuilder(fragment.requireContext()) - .setView(R.layout.permission_allow_location_dialog) - .setPositiveButton(R.string.Permissions_continue) { _, _ -> - Permissions.with(fragment) - .request(Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION) - .ifNecessary() - .withPermanentDenialDialog(fragment.getString(R.string.AttachmentManager_signal_requires_location_information_in_order_to_attach_a_location), null, R.string.AttachmentManager_signal_allow_access_location, R.string.AttachmentManager_signal_to_send_location, fragment.parentFragmentManager) - .onAnyDenied { Toast.makeText(fragment.requireContext(), R.string.AttachmentManager_signal_needs_location_access, Toast.LENGTH_LONG).show() } - .onSomeGranted { selectLocationLauncher.launch(chatColors) } - .execute() - } - .setNegativeButton(R.string.Permissions_not_now) { d, _ -> - Toast.makeText(fragment.requireContext(), R.string.AttachmentManager_signal_needs_location_access, Toast.LENGTH_LONG).show() - d.dismiss() - } - .create() - dialog.show() + Permissions.with(fragment) + .request(Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION) + .ifNecessary() + .withRationaleDialog(fragment.getString(R.string.AttachmentManager_signal_allow_access_location), fragment.getString(R.string.AttachmentManager_signal_allow_signal_access_location), R.drawable.symbol_location_white_24) + .withPermanentDenialDialog(fragment.getString(R.string.AttachmentManager_signal_requires_location_information_in_order_to_attach_a_location), null, R.string.AttachmentManager_signal_allow_access_location, R.string.AttachmentManager_signal_to_send_location, fragment.parentFragmentManager) + .onAnyDenied { Toast.makeText(fragment.requireContext(), R.string.AttachmentManager_signal_needs_location_access, Toast.LENGTH_LONG).show() } + .onSomeGranted { selectLocationLauncher.launch(chatColors) } + .execute() } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationFragment.kt index 171dd4ad20..044582a34e 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationFragment.kt @@ -3975,8 +3975,9 @@ class ConversationFragment : .with(this@ConversationFragment) .request(Manifest.permission.RECORD_AUDIO) .ifNecessary() - .withRationaleDialog(getString(R.string.ConversationActivity_to_send_audio_messages_allow_signal_access_to_your_microphone), R.drawable.ic_mic_solid_24) - .withPermanentDenialDialog(getString(R.string.ConversationActivity_signal_requires_the_microphone_permission_in_order_to_send_audio_messages)) + .withRationaleDialog(getString(R.string.ConversationActivity_allow_access_microphone), getString(R.string.ConversationActivity_to_send_voice_messages_allow_signal_access_to_your_microphone), R.drawable.ic_mic_24) + .withPermanentDenialDialog(getString(R.string.ConversationActivity_signal_requires_the_microphone_permission_in_order_to_send_audio_messages), null, R.string.ConversationActivity_allow_access_microphone, R.string.ConversationActivity_signal_to_send_audio_messages, this@ConversationFragment.parentFragmentManager) + .onAnyDenied { Toast.makeText(this@ConversationFragment.requireContext(), R.string.ConversationActivity_signal_needs_microphone_access_voice_message, Toast.LENGTH_LONG).show() } .execute() } diff --git a/app/src/main/java/org/thoughtcrime/securesms/permissions/Permissions.java b/app/src/main/java/org/thoughtcrime/securesms/permissions/Permissions.java index a8910f546a..fb30608b5a 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/permissions/Permissions.java +++ b/app/src/main/java/org/thoughtcrime/securesms/permissions/Permissions.java @@ -73,6 +73,8 @@ public class Permissions { private @DrawableRes int[] rationalDialogHeader; private String rationaleDialogMessage; + private String rationaleDialogTitle; + private String rationaleDialogDetails; private boolean rationaleDialogCancelable; private boolean ifNecesary; @@ -104,8 +106,18 @@ public class Permissions { } public PermissionsBuilder withRationaleDialog(@NonNull String message, boolean cancelable, @NonNull @DrawableRes int... headers) { + return withRationaleDialog(message, null, null, cancelable, headers); + } + + public PermissionsBuilder withRationaleDialog(@NonNull String title, @NonNull String details, @NonNull @DrawableRes int... headers) { + return withRationaleDialog(null, title, details, true, headers); + } + + public PermissionsBuilder withRationaleDialog(@Nullable String message, @Nullable String title, @Nullable String details, boolean cancelable, @NonNull @DrawableRes int... headers) { this.rationalDialogHeader = headers; this.rationaleDialogMessage = message; + this.rationaleDialogTitle = title; + this.rationaleDialogDetails = details; this.rationaleDialogCancelable = cancelable; return this; } @@ -164,7 +176,8 @@ public class Permissions { if (ifNecesary && (permissionObject.hasAll(requestedPermissions) || !condition)) { executePreGrantedPermissionsRequest(request); - } else if (rationaleDialogMessage != null && rationalDialogHeader != null) { + } else if ((rationaleDialogMessage != null || (rationaleDialogTitle != null && rationaleDialogDetails != null)) + && rationalDialogHeader != null) { executePermissionsRequestWithRationale(request); } else { executePermissionsRequest(request); @@ -180,13 +193,17 @@ public class Permissions { @SuppressWarnings("ConstantConditions") private void executePermissionsRequestWithRationale(PermissionsRequest request) { - RationaleDialog.createFor(permissionObject.getContext(), rationaleDialogMessage, rationalDialogHeader) - .setPositiveButton(R.string.Permissions_continue, (dialog, which) -> executePermissionsRequest(request)) - .setNegativeButton(R.string.Permissions_not_now, (dialog, which) -> executeNoPermissionsRequest(request)) - .setCancelable(rationaleDialogCancelable) - .show() - .getWindow() - .setLayout((int)(permissionObject.getWindowWidth() * .75), ViewGroup.LayoutParams.WRAP_CONTENT); + MaterialAlertDialogBuilder builder = (rationaleDialogMessage != null) + ? RationaleDialog.createFor(permissionObject.getContext(), rationaleDialogMessage, rationalDialogHeader) + : RationaleDialog.createFor(permissionObject.getContext(), rationaleDialogTitle, rationaleDialogDetails, rationalDialogHeader); + builder.setPositiveButton(R.string.Permissions_continue, (dialog, which) -> executePermissionsRequest(request)) + .setNegativeButton(R.string.Permissions_not_now, (dialog, which) -> executeNoPermissionsRequest(request)) + .setCancelable(rationaleDialogCancelable); + if (rationaleDialogMessage != null) { + builder.show().getWindow().setLayout((int)(permissionObject.getWindowWidth() * .75), ViewGroup.LayoutParams.WRAP_CONTENT); + } else { + builder.show(); + } } private void executePermissionsRequest(PermissionsRequest request) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/permissions/RationaleDialog.java b/app/src/main/java/org/thoughtcrime/securesms/permissions/RationaleDialog.java index f5f72e1790..2d3377b11b 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/permissions/RationaleDialog.java +++ b/app/src/main/java/org/thoughtcrime/securesms/permissions/RationaleDialog.java @@ -29,6 +29,44 @@ import java.util.Objects; public class RationaleDialog { + public static MaterialAlertDialogBuilder createFor(@NonNull Context context, @NonNull String title, @NonNull String details, @DrawableRes int... drawables) { + View view = LayoutInflater.from(context).inflate(R.layout.permission_allow_dialog, null); + ViewGroup header = view.findViewById(R.id.permission_header_container); + TextView titleText = view.findViewById(R.id.permission_title); + TextView detailsText = view.findViewById(R.id.permission_details); + int iconSize = (int) DimensionUnit.DP.toPixels(32); + + for (int i = 0; i < drawables.length; i++) { + Drawable drawable = Objects.requireNonNull(ContextCompat.getDrawable(context, drawables[i])); + DrawableCompat.setTint(drawable, ContextCompat.getColor(context, R.color.signal_colorOnPrimaryContainer)); + + ImageView imageView = new ImageView(context); + imageView.setImageDrawable(drawable); + imageView.setLayoutParams(new LayoutParams(iconSize, iconSize)); + imageView.setScaleType(ImageView.ScaleType.FIT_CENTER); + + header.addView(imageView); + + if (i != drawables.length - 1) { + TextView plus = new TextView(context); + plus.setText("+"); + plus.setTextSize(TypedValue.COMPLEX_UNIT_SP, 40); + plus.setTextColor(Color.WHITE); + + LayoutParams layoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); + layoutParams.setMargins(ViewUtil.dpToPx(context, 20), 0, ViewUtil.dpToPx(context, 20), 0); + + plus.setLayoutParams(layoutParams); + header.addView(plus); + } + } + + titleText.setText(title); + detailsText.setText(details); + + return new MaterialAlertDialogBuilder(context).setView(view); + } + public static MaterialAlertDialogBuilder createFor(@NonNull Context context, @NonNull String message, @DrawableRes int... drawables) { View view = LayoutInflater.from(context).inflate(R.layout.permissions_rationale_dialog, null); ViewGroup header = view.findViewById(R.id.header_container); diff --git a/app/src/main/res/layout/permission_allow_location_dialog.xml b/app/src/main/res/layout/permission_allow_dialog.xml similarity index 54% rename from app/src/main/res/layout/permission_allow_location_dialog.xml rename to app/src/main/res/layout/permission_allow_dialog.xml index 40398b2b4d..980ee79484 100644 --- a/app/src/main/res/layout/permission_allow_location_dialog.xml +++ b/app/src/main/res/layout/permission_allow_dialog.xml @@ -1,35 +1,38 @@ - + android:gravity="center" + android:layout_gravity="center" + android:orientation="horizontal" + android:layout_marginBottom="10dp"> + + + tools:text="@string/AttachmentManager_signal_allow_access_location" /> + tools:text="@string/AttachmentManager_signal_allow_signal_access_location" /> diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 669e328a84..bcc23be6f2 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -396,8 +396,16 @@ Your request to join has been sent to the group admin. You\'ll be notified when they take action. Cancel Request - To send audio messages, allow Signal access to your microphone. + + Allow access to your microphone + + To send audio messages: + + To send voice messages, allow Signal access to your microphone. + + Signal needs microphone access to record a voice message. Signal requires the Microphone permission in order to send audio messages, but it has been permanently denied. Please continue to app settings, select \"Permissions\", and enable \"Microphone\". + Signal needs the Microphone and Camera permissions in order to call %s, but they have been permanently denied. Please continue to app settings, select \"Permissions\", and enable \"Microphone\" and \"Camera\". To capture photos and video, allow Signal access to the camera. Signal needs the Camera permission to take photos or video, but it has been permanently denied. Please continue to app settings, select \"Permissions\", and enable \"Camera\".