Update microphone permission UI for voice messages.

This commit is contained in:
mtang-signal
2024-04-29 09:39:07 -04:00
committed by Greyson Parrelli
parent 69c40a6835
commit c5c0c432c4
6 changed files with 98 additions and 41 deletions

View File

@@ -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()
}
}

View File

@@ -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()
}

View File

@@ -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) {

View File

@@ -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);

View File

@@ -1,35 +1,38 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="20dp"
android:paddingTop="20dp"
android:paddingHorizontal="20dp"
tools:viewBindingIgnore="true">
<ImageView
android:layout_width="match_parent"
<LinearLayout
android:id="@+id/permission_header_container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:importantForAccessibility="no"
app:tint="@color/signal_colorOnPrimaryContainer"
app:srcCompat="@drawable/symbol_location_white_24" />
android:gravity="center"
android:layout_gravity="center"
android:orientation="horizontal"
android:layout_marginBottom="10dp">
</LinearLayout>
<TextView
android:id="@+id/allow_location_title"
android:id="@+id/permission_title"
style="@style/Signal.Text.Title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="@string/AttachmentManager_signal_allow_access_location" />
tools:text="@string/AttachmentManager_signal_allow_access_location" />
<TextView
android:id="@+id/allow_location_body"
android:id="@+id/permission_details"
style="@style/Signal.Text.BodySmall"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="15dp"
android:text="@string/AttachmentManager_signal_allow_signal_access_location" />
tools:text="@string/AttachmentManager_signal_allow_signal_access_location" />
</LinearLayout>

View File

@@ -396,8 +396,16 @@
<string name="ConversationActivity_your_request_to_join_has_been_sent_to_the_group_admin">Your request to join has been sent to the group admin. You\'ll be notified when they take action.</string>
<string name="ConversationActivity_cancel_request">Cancel Request</string>
<string name="ConversationActivity_to_send_audio_messages_allow_signal_access_to_your_microphone">To send audio messages, allow Signal access to your microphone.</string>
<!-- Dialog title asking users for microphone permission -->
<string name="ConversationActivity_allow_access_microphone">Allow access to your microphone</string>
<!-- Dialog description that will explain the steps needed to give microphone permissions -->
<string name="ConversationActivity_signal_to_send_audio_messages">To send audio messages:</string>
<!-- Alert dialog description asking for microphone permission in order to send voice messages -->
<string name="ConversationActivity_to_send_voice_messages_allow_signal_access_to_your_microphone">To send voice messages, allow Signal access to your microphone.</string>
<!-- Toast text explaining Signal's need for microphone access -->
<string name="ConversationActivity_signal_needs_microphone_access_voice_message">Signal needs microphone access to record a voice message.</string>
<string name="ConversationActivity_signal_requires_the_microphone_permission_in_order_to_send_audio_messages">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\".</string>
<string name="ConversationActivity_signal_needs_the_microphone_and_camera_permissions_in_order_to_call_s">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\".</string>
<string name="ConversationActivity_to_capture_photos_and_video_allow_signal_access_to_the_camera">To capture photos and video, allow Signal access to the camera.</string>
<string name="ConversationActivity_signal_needs_the_camera_permission_to_take_photos_or_video">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\".</string>