mirror of
https://github.com/ArcaneChat/android.git
synced 2026-07-03 14:05:24 +02:00
improve screen reader support in conversations
This commit is contained in:
@@ -15,7 +15,7 @@
|
|||||||
android:src="@drawable/msg_encr_out"
|
android:src="@drawable/msg_encr_out"
|
||||||
android:visibility="gone"
|
android:visibility="gone"
|
||||||
android:layout_gravity="center_vertical|end"
|
android:layout_gravity="center_vertical|end"
|
||||||
android:contentDescription="@string/chat_input_placeholder"
|
android:importantForAccessibility="no"
|
||||||
tools:visibility="visible"/>
|
tools:visibility="visible"/>
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
|
|||||||
@@ -164,6 +164,7 @@
|
|||||||
android:paddingTop="@dimen/message_bubble_top_padding"
|
android:paddingTop="@dimen/message_bubble_top_padding"
|
||||||
android:textColor="?conversation_item_incoming_text_primary_color"
|
android:textColor="?conversation_item_incoming_text_primary_color"
|
||||||
android:textColorLink="?conversation_item_incoming_text_primary_color"
|
android:textColorLink="?conversation_item_incoming_text_primary_color"
|
||||||
|
android:importantForAccessibility="no"
|
||||||
app:scaleEmojis="true"
|
app:scaleEmojis="true"
|
||||||
tools:text="Mango pickle lorem ipsum"/>
|
tools:text="Mango pickle lorem ipsum"/>
|
||||||
|
|
||||||
|
|||||||
@@ -142,6 +142,7 @@
|
|||||||
android:paddingTop="@dimen/message_bubble_top_padding"
|
android:paddingTop="@dimen/message_bubble_top_padding"
|
||||||
android:textColor="?conversation_item_outgoing_text_primary_color"
|
android:textColor="?conversation_item_outgoing_text_primary_color"
|
||||||
android:textColorLink="?conversation_item_outgoing_text_primary_color"
|
android:textColorLink="?conversation_item_outgoing_text_primary_color"
|
||||||
|
android:importantForAccessibility="no"
|
||||||
app:scaleEmojis="true"
|
app:scaleEmojis="true"
|
||||||
tools:text="Mango pickle lorem ipsum"/>
|
tools:text="Mango pickle lorem ipsum"/>
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package org.thoughtcrime.securesms;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
import android.view.accessibility.AccessibilityManager;
|
||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
@@ -77,6 +78,8 @@ public abstract class BaseConversationItem extends LinearLayout
|
|||||||
return batchSelected.isEmpty() && (messageRecord.isFailed());
|
return batchSelected.isEmpty() && (messageRecord.isFailed());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void onAccessibilityClick() {}
|
||||||
|
|
||||||
protected class PassthroughClickListener implements View.OnLongClickListener, View.OnClickListener {
|
protected class PassthroughClickListener implements View.OnLongClickListener, View.OnClickListener {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -103,6 +106,9 @@ public abstract class BaseConversationItem extends LinearLayout
|
|||||||
|
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
if (!shouldInterceptClicks(messageRecord) && parent != null) {
|
if (!shouldInterceptClicks(messageRecord) && parent != null) {
|
||||||
|
if (batchSelected.isEmpty() && ((AccessibilityManager) context.getSystemService(Context.ACCESSIBILITY_SERVICE)).isTouchExplorationEnabled()) {
|
||||||
|
BaseConversationItem.this.onAccessibilityClick();
|
||||||
|
}
|
||||||
parent.onClick(v);
|
parent.onClick(v);
|
||||||
} else if (messageRecord.isFailed()) {
|
} else if (messageRecord.isFailed()) {
|
||||||
View view = View.inflate(context, R.layout.message_details_view, null);
|
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.Color;
|
||||||
import android.graphics.PorterDuff;
|
import android.graphics.PorterDuff;
|
||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
|
import android.os.Build;
|
||||||
import android.text.SpannableString;
|
import android.text.SpannableString;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
@@ -193,6 +194,7 @@ public class ConversationItem extends BaseConversationItem
|
|||||||
setReactions(messageRecord);
|
setReactions(messageRecord);
|
||||||
setFooter(messageRecord, locale);
|
setFooter(messageRecord, locale);
|
||||||
setQuote(messageRecord);
|
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) {
|
private boolean hasAudio(DcMsg messageRecord) {
|
||||||
int type = messageRecord.getType();
|
int type = messageRecord.getType();
|
||||||
return type==DcMsg.DC_MSG_AUDIO || type==DcMsg.DC_MSG_VOICE;
|
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().setAudio(new AudioSlide(context, messageRecord), duration);
|
||||||
audioViewStub.get().setOnLongClickListener(passthroughClickListener);
|
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(bodyText, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||||
ViewUtil.updateLayoutParams(groupSenderHolder, 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().setDocument(new DocumentSlide(context, messageRecord));
|
||||||
documentViewStub.get().setDocumentClickListener(new ThumbnailClickListener());
|
documentViewStub.get().setDocumentClickListener(new ThumbnailClickListener());
|
||||||
documentViewStub.get().setOnLongClickListener(passthroughClickListener);
|
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(bodyText, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||||
ViewUtil.updateLayoutParams(groupSenderHolder, 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().setWebxdc(messageRecord, context.getString(R.string.webxdc_app));
|
||||||
webxdcViewStub.get().setWebxdcClickListener(new ThumbnailClickListener());
|
webxdcViewStub.get().setWebxdcClickListener(new ThumbnailClickListener());
|
||||||
webxdcViewStub.get().setOnLongClickListener(passthroughClickListener);
|
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(bodyText, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||||
ViewUtil.updateLayoutParams(groupSenderHolder, 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().setOnLongClickListener(passthroughClickListener);
|
||||||
mediaThumbnailStub.get().setOnClickListener(passthroughClickListener);
|
mediaThumbnailStub.get().setOnClickListener(passthroughClickListener);
|
||||||
mediaThumbnailStub.get().showShade(TextUtils.isEmpty(messageRecord.getText()));
|
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);
|
setThumbnailOutlineCorners(messageRecord, showSender);
|
||||||
|
|
||||||
@@ -531,9 +575,11 @@ public class ConversationItem extends BaseConversationItem
|
|||||||
|
|
||||||
stickerStub.get().setSlide(glideRequests, new StickerSlide(context, messageRecord));
|
stickerStub.get().setSlide(glideRequests, new StickerSlide(context, messageRecord));
|
||||||
stickerStub.get().setThumbnailClickListener(new StickerClickListener());
|
stickerStub.get().setThumbnailClickListener(new StickerClickListener());
|
||||||
|
|
||||||
stickerStub.get().setOnLongClickListener(passthroughClickListener);
|
stickerStub.get().setOnLongClickListener(passthroughClickListener);
|
||||||
stickerStub.get().setOnClickListener(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(bodyText, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||||
ViewUtil.updateLayoutParams(groupSenderHolder, 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;
|
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
|
/// Event handlers
|
||||||
|
|
||||||
private class ThumbnailClickListener implements SlideClickListener {
|
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) {
|
public void setDuration(int duration) {
|
||||||
if (getProgress()==0)
|
if (getProgress()==0)
|
||||||
this.timestamp.setText(DateUtils.getFormatedDuration(duration));
|
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)
|
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());
|
setTouchDelegate(thumbnail.getTouchDelegate());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getDescription() {
|
||||||
|
return thumbnail.getDescription() + "\n" + footer.getDescription();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onMeasure(int originalWidthMeasureSpec, int originalHeightMeasureSpec) {
|
protected void onMeasure(int originalWidthMeasureSpec, int originalHeightMeasureSpec) {
|
||||||
int width = MeasureSpec.getSize(originalWidthMeasureSpec);
|
int width = MeasureSpec.getSize(originalWidthMeasureSpec);
|
||||||
@@ -185,6 +189,11 @@ public class ConversationItemThumbnail extends FrameLayout {
|
|||||||
thumbnail.setThumbnailClickListener(listener);
|
thumbnail.setThumbnailClickListener(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean performClick() {
|
||||||
|
return thumbnail.performClick();
|
||||||
|
}
|
||||||
|
|
||||||
@UiThread
|
@UiThread
|
||||||
public void setImageResource(@NonNull GlideRequests glideRequests, @NonNull Slide slide,
|
public void setImageResource(@NonNull GlideRequests glideRequests, @NonNull Slide slide,
|
||||||
int naturalWidth, int naturalHeight)
|
int naturalWidth, int naturalHeight)
|
||||||
|
|||||||
@@ -123,4 +123,11 @@ public class DeliveryStatusView {
|
|||||||
public void resetTint() {
|
public void resetTint() {
|
||||||
deliveryIndicator.setColorFilter(null);
|
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));
|
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
|
@Override
|
||||||
public void setFocusable(boolean focusable) {
|
public void setFocusable(boolean focusable) {
|
||||||
super.setFocusable(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
|
@Override
|
||||||
protected void onMeasure(int originalWidthMeasureSpec, int originalHeightMeasureSpec) {
|
protected void onMeasure(int originalWidthMeasureSpec, int originalHeightMeasureSpec) {
|
||||||
fillTargetDimensions(measureDimens, dimens, bounds);
|
fillTargetDimensions(measureDimens, dimens, bounds);
|
||||||
|
|||||||
@@ -89,6 +89,15 @@ public class WebxdcView extends FrameLayout {
|
|||||||
appSubtitle.setText(summary);
|
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 class OpenClickedListener implements View.OnClickListener {
|
||||||
private final @NonNull DocumentSlide slide;
|
private final @NonNull DocumentSlide slide;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user