improve screen reader support in conversations

This commit is contained in:
adbenitez
2023-10-03 21:46:36 +02:00
parent 479305198c
commit 1e149eef83
12 changed files with 137 additions and 2 deletions
+1 -1
View File
@@ -15,7 +15,7 @@
android:src="@drawable/msg_encr_out"
android:visibility="gone"
android:layout_gravity="center_vertical|end"
android:contentDescription="@string/chat_input_placeholder"
android:importantForAccessibility="no"
tools:visibility="visible"/>
<TextView
@@ -164,6 +164,7 @@
android:paddingTop="@dimen/message_bubble_top_padding"
android:textColor="?conversation_item_incoming_text_primary_color"
android:textColorLink="?conversation_item_incoming_text_primary_color"
android:importantForAccessibility="no"
app:scaleEmojis="true"
tools:text="Mango pickle lorem ipsum"/>
+1
View File
@@ -142,6 +142,7 @@
android:paddingTop="@dimen/message_bubble_top_padding"
android:textColor="?conversation_item_outgoing_text_primary_color"
android:textColorLink="?conversation_item_outgoing_text_primary_color"
android:importantForAccessibility="no"
app:scaleEmojis="true"
tools:text="Mango pickle lorem ipsum"/>
@@ -3,6 +3,7 @@ package org.thoughtcrime.securesms;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.view.accessibility.AccessibilityManager;
import android.widget.LinearLayout;
import android.widget.TextView;
@@ -77,6 +78,8 @@ public abstract class BaseConversationItem extends LinearLayout
return batchSelected.isEmpty() && (messageRecord.isFailed());
}
protected void onAccessibilityClick() {}
protected class PassthroughClickListener implements View.OnLongClickListener, View.OnClickListener {
@Override
@@ -103,6 +106,9 @@ public abstract class BaseConversationItem extends LinearLayout
public void onClick(View v) {
if (!shouldInterceptClicks(messageRecord) && parent != null) {
if (batchSelected.isEmpty() && ((AccessibilityManager) context.getSystemService(Context.ACCESSIBILITY_SERVICE)).isTouchExplorationEnabled()) {
BaseConversationItem.this.onAccessibilityClick();
}
parent.onClick(v);
} else if (messageRecord.isFailed()) {
View view = View.inflate(context, R.layout.message_details_view, null);
@@ -22,6 +22,7 @@ import android.content.res.TypedArray;
import android.graphics.Color;
import android.graphics.PorterDuff;
import android.graphics.Rect;
import android.os.Build;
import android.text.SpannableString;
import android.text.TextUtils;
import android.util.AttributeSet;
@@ -193,6 +194,7 @@ public class ConversationItem extends BaseConversationItem
setReactions(messageRecord);
setFooter(messageRecord, locale);
setQuote(messageRecord);
setContentDescription(messageRecord);
}
@@ -305,6 +307,36 @@ public class ConversationItem extends BaseConversationItem
}
}
private void setContentDescription(DcMsg messageRecord) {
String desc = "";
if (groupSenderHolder.getVisibility() == View.VISIBLE) {
desc = groupSender.getText() + "\n";
}
if (audioViewStub.resolved() && audioViewStub.get().getVisibility() == View.VISIBLE) {
desc += audioViewStub.get().getDescription() + "\n";
} else if (documentViewStub.resolved() && documentViewStub.get().getVisibility() == View.VISIBLE) {
desc += documentViewStub.get().getDescription() + "\n";
} else if (webxdcViewStub.resolved() && webxdcViewStub.get().getVisibility() == View.VISIBLE) {
desc += webxdcViewStub.get().getDescription() + "\n";
} else if (mediaThumbnailStub.resolved() && mediaThumbnailStub.get().getVisibility() == View.VISIBLE) {
desc += mediaThumbnailStub.get().getDescription() + "\n";
} else if (stickerStub.resolved() && stickerStub.get().getVisibility() == View.VISIBLE) {
desc += context.getString(R.string.sticker) + "\n";
}
if (bodyText.getVisibility() == View.VISIBLE) {
desc += bodyText.getText() + "\n";
}
if (footer.getVisibility() == View.VISIBLE) {
desc += footer.getDescription() + "\n";
} else if (stickerFooter.getVisibility() == View.VISIBLE) {
desc += stickerFooter.getDescription() + "\n";
}
this.setContentDescription(desc);
}
private boolean hasAudio(DcMsg messageRecord) {
int type = messageRecord.getType();
return type==DcMsg.DC_MSG_AUDIO || type==DcMsg.DC_MSG_VOICE;
@@ -447,6 +479,9 @@ public class ConversationItem extends BaseConversationItem
audioViewStub.get().setAudio(new AudioSlide(context, messageRecord), duration);
audioViewStub.get().setOnLongClickListener(passthroughClickListener);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
audioViewStub.get().setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
}
ViewUtil.updateLayoutParams(bodyText, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
ViewUtil.updateLayoutParams(groupSenderHolder, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
@@ -463,6 +498,9 @@ public class ConversationItem extends BaseConversationItem
documentViewStub.get().setDocument(new DocumentSlide(context, messageRecord));
documentViewStub.get().setDocumentClickListener(new ThumbnailClickListener());
documentViewStub.get().setOnLongClickListener(passthroughClickListener);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
documentViewStub.get().setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
}
ViewUtil.updateLayoutParams(bodyText, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
ViewUtil.updateLayoutParams(groupSenderHolder, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
@@ -478,6 +516,9 @@ public class ConversationItem extends BaseConversationItem
webxdcViewStub.get().setWebxdc(messageRecord, context.getString(R.string.webxdc_app));
webxdcViewStub.get().setWebxdcClickListener(new ThumbnailClickListener());
webxdcViewStub.get().setOnLongClickListener(passthroughClickListener);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
webxdcViewStub.get().setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
}
ViewUtil.updateLayoutParams(bodyText, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
ViewUtil.updateLayoutParams(groupSenderHolder, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
@@ -512,6 +553,9 @@ public class ConversationItem extends BaseConversationItem
mediaThumbnailStub.get().setOnLongClickListener(passthroughClickListener);
mediaThumbnailStub.get().setOnClickListener(passthroughClickListener);
mediaThumbnailStub.get().showShade(TextUtils.isEmpty(messageRecord.getText()));
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
mediaThumbnailStub.get().setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
}
setThumbnailOutlineCorners(messageRecord, showSender);
@@ -531,9 +575,11 @@ public class ConversationItem extends BaseConversationItem
stickerStub.get().setSlide(glideRequests, new StickerSlide(context, messageRecord));
stickerStub.get().setThumbnailClickListener(new StickerClickListener());
stickerStub.get().setOnLongClickListener(passthroughClickListener);
stickerStub.get().setOnClickListener(passthroughClickListener);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
stickerStub.get().setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
}
ViewUtil.updateLayoutParams(bodyText, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
ViewUtil.updateLayoutParams(groupSenderHolder, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
@@ -792,6 +838,14 @@ public class ConversationItem extends BaseConversationItem
return availableWidth;
}
@Override
public void onAccessibilityClick() {
if (mediaThumbnailStub.resolved()) mediaThumbnailStub.get().performClick();
else if (audioViewStub.resolved()) audioViewStub.get().performClick();
else if (documentViewStub.resolved()) documentViewStub.get().performClick();
else if (webxdcViewStub.resolved()) webxdcViewStub.get().performClick();
}
/// Event handlers
private class ThumbnailClickListener implements SlideClickListener {
@@ -93,6 +93,30 @@ public class AudioView extends FrameLayout implements AudioSlidePlayer.Listener
}
}
@Override
public boolean performClick() {
if (this.playButton.getVisibility() == View.VISIBLE) {
playButton.performClick();
} else {
pauseButton.performClick();
}
return super.performClick();
}
public String getDescription() {
String desc;
if (this.title.getVisibility() == View.VISIBLE) {
desc = getContext().getString(R.string.audio);
} else {
desc = getContext().getString(R.string.voice_message);
}
desc += "\n" + this.timestamp.getText();
if (title.getVisibility() == View.VISIBLE) {
desc += "\n" + this.title.getText();
}
return desc;
}
public void setDuration(int duration) {
if (getProgress()==0)
this.timestamp.setText(DateUtils.getFormatedDuration(duration));
@@ -100,4 +100,13 @@ public class ConversationItemFooter extends LinearLayout {
deliveryStatusView.setTint(textColor); // Reset the color to the standard color (because the footer is re-used in a RecyclerView)
}
}
public String getDescription() {
String desc = dateView.getText().toString();
String deliveryDesc = deliveryStatusView.getDescription();
if (!"".equals(deliveryDesc)) {
desc += "\n" + deliveryDesc;
}
return desc;
}
}
@@ -86,6 +86,10 @@ public class ConversationItemThumbnail extends FrameLayout {
setTouchDelegate(thumbnail.getTouchDelegate());
}
public String getDescription() {
return thumbnail.getDescription() + "\n" + footer.getDescription();
}
@Override
protected void onMeasure(int originalWidthMeasureSpec, int originalHeightMeasureSpec) {
int width = MeasureSpec.getSize(originalWidthMeasureSpec);
@@ -185,6 +189,11 @@ public class ConversationItemThumbnail extends FrameLayout {
thumbnail.setThumbnailClickListener(listener);
}
@Override
public boolean performClick() {
return thumbnail.performClick();
}
@UiThread
public void setImageResource(@NonNull GlideRequests glideRequests, @NonNull Slide slide,
int naturalWidth, int naturalHeight)
@@ -123,4 +123,11 @@ public class DeliveryStatusView {
public void resetTint() {
deliveryIndicator.setColorFilter(null);
}
public String getDescription() {
if (deliveryIndicator.getVisibility() == View.VISIBLE) {
return deliveryIndicator.getContentDescription().toString();
}
return "";
}
}
@@ -59,6 +59,13 @@ public class DocumentView extends FrameLayout {
this.setOnClickListener(new OpenClickedListener(documentSlide));
}
public String getDescription() {
String desc = getContext().getString(R.string.file);
desc += "\n" + fileName.getText();
desc += "\n" + fileSize.getText();
return desc;
}
@Override
public void setFocusable(boolean focusable) {
super.setFocusable(focusable);
@@ -82,6 +82,14 @@ public class ThumbnailView extends FrameLayout {
}
public String getDescription() {
if (slide != null && slide.hasPlayOverlay()) {
return getContext().getString(R.string.video);
} else {
return getContext().getString(R.string.image);
}
}
@Override
protected void onMeasure(int originalWidthMeasureSpec, int originalHeightMeasureSpec) {
fillTargetDimensions(measureDimens, dimens, bounds);
@@ -89,6 +89,15 @@ public class WebxdcView extends FrameLayout {
appSubtitle.setText(summary);
}
public String getDescription() {
String desc = getContext().getString(R.string.webxdc_app);
desc += "\n" + appName.getText();
if (appSubtitle.getText() != null && !appSubtitle.getText().toString().equals("") && !appSubtitle.getText().toString().equals(getContext().getString(R.string.webxdc_app))) {
desc += "\n" + appSubtitle.getText();
}
return desc;
}
private class OpenClickedListener implements View.OnClickListener {
private final @NonNull DocumentSlide slide;