Accessibility improvements

TalkBack functions properly with MessageList items, as well as
"reply," "reply-all," and "forward" buttons while viewing messages.
It is now also possible to switch accounts using only a dpad
or trackball. Finally, EditText fields in account setup also work
with TalkBack now.

Checkmarks don't work with Talkback, but this I have confirmed and
reported it as frameworks bug.

Change-Id: I7f72682a517eef4fa122241c675026fe7997ac64
This commit is contained in:
Jorge Lugo 2011-06-23 14:51:19 -07:00
parent 5e52339306
commit 8e779e627a
10 changed files with 76 additions and 16 deletions

View File

@ -50,6 +50,7 @@
android:id="@+id/account_email" android:id="@+id/account_email"
android:layout_width="@dimen/setup_credentials_input_width" android:layout_width="@dimen/setup_credentials_input_width"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:contentDescription="@string/account_setup_basics_email_label"
android:inputType="textEmailAddress" android:inputType="textEmailAddress"
android:imeOptions="actionNext" /> android:imeOptions="actionNext" />
</TableRow> </TableRow>
@ -64,6 +65,7 @@
android:id="@+id/account_password" android:id="@+id/account_password"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_width="@dimen/setup_credentials_input_width" android:layout_width="@dimen/setup_credentials_input_width"
android:contentDescription="@string/account_setup_basics_password_label"
android:inputType="textPassword" android:inputType="textPassword"
android:imeOptions="actionDone" android:imeOptions="actionDone"
android:nextFocusDown="@+id/next" /> android:nextFocusDown="@+id/next" />

View File

@ -21,8 +21,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:paddingLeft="@dimen/setup_item_inset_left" android:paddingLeft="@dimen/setup_item_inset_left"
android:paddingRight="@dimen/setup_item_inset_right" android:paddingRight="@dimen/setup_item_inset_right" >
>
<TextView <TextView
android:id="@+id/account_description_label" android:id="@+id/account_description_label"
android:layout_alignParentTop="true" android:layout_alignParentTop="true"
@ -35,6 +34,7 @@
android:layout_below="@+id/account_description_label" android:layout_below="@+id/account_description_label"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_width="match_parent" android:layout_width="match_parent"
android:contentDescription="@string/account_setup_names_account_name_label"
android:inputType="textCapWords" android:inputType="textCapWords"
android:imeOptions="actionDone" /> android:imeOptions="actionDone" />
<TextView <TextView
@ -50,6 +50,7 @@
android:layout_below="@+id/account_name_label" android:layout_below="@+id/account_name_label"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_width="match_parent" android:layout_width="match_parent"
android:contentDescription="@string/account_setup_names_user_name_label"
android:inputType="textPersonName" android:inputType="textPersonName"
android:imeOptions="actionDone" /> android:imeOptions="actionDone" />
</RelativeLayout> </RelativeLayout>

View File

@ -95,6 +95,7 @@
<ImageButton <ImageButton
android:id="@+id/reply" android:id="@+id/reply"
android:layout_marginRight="16dip" android:layout_marginRight="16dip"
android:contentDescription="@string/reply_action"
android:src="@drawable/ic_reply" android:src="@drawable/ic_reply"
android:visibility="gone" android:visibility="gone"
style="@style/message_view_action_buttons" style="@style/message_view_action_buttons"
@ -102,6 +103,7 @@
<ImageButton <ImageButton
android:id="@+id/reply_all" android:id="@+id/reply_all"
android:layout_marginRight="16dip" android:layout_marginRight="16dip"
android:contentDescription="@string/reply_all_action"
android:src="@drawable/ic_reply_all" android:src="@drawable/ic_reply_all"
android:visibility="gone" android:visibility="gone"
style="@style/message_view_action_buttons" style="@style/message_view_action_buttons"
@ -109,6 +111,7 @@
<ImageButton <ImageButton
android:id="@+id/forward" android:id="@+id/forward"
android:layout_marginRight="16dip" android:layout_marginRight="16dip"
android:contentDescription="@string/forward_action"
android:src="@drawable/ic_forward" android:src="@drawable/ic_forward"
android:visibility="gone" android:visibility="gone"
style="@style/message_view_action_buttons" style="@style/message_view_action_buttons"

View File

@ -36,6 +36,7 @@
<EditText <EditText
android:id="@+id/account_email" android:id="@+id/account_email"
android:hint="@string/account_setup_basics_email_label" android:hint="@string/account_setup_basics_email_label"
android:contentDescription="@string/account_setup_basics_email_label"
android:inputType="textEmailAddress" android:inputType="textEmailAddress"
android:imeOptions="actionNext" android:imeOptions="actionNext"
android:layout_below="@+id/instructions" android:layout_below="@+id/instructions"
@ -44,6 +45,7 @@
<EditText <EditText
android:id="@+id/account_password" android:id="@+id/account_password"
android:hint="@string/account_setup_basics_password_label" android:hint="@string/account_setup_basics_password_label"
android:contentDescription="@string/account_setup_basics_password_label"
android:inputType="textPassword" android:inputType="textPassword"
android:imeOptions="actionDone" android:imeOptions="actionDone"
android:layout_below="@+id/account_email" android:layout_below="@+id/account_email"

View File

@ -25,36 +25,38 @@
android:layout_weight="1" android:layout_weight="1"
android:orientation="vertical" > android:orientation="vertical" >
<TextView <TextView
android:text="@string/account_setup_names_headline"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_width="match_parent" android:layout_width="match_parent"
android:text="@string/account_setup_names_headline"
android:textAppearance="?android:attr/textAppearanceMedium" android:textAppearance="?android:attr/textAppearanceMedium"
android:textColor="?android:attr/textColorPrimary" /> android:textColor="?android:attr/textColorPrimary" />
<TextView <TextView
android:text="@string/account_setup_names_account_name_label"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_width="match_parent" android:layout_width="match_parent"
android:text="@string/account_setup_names_account_name_label"
android:textAppearance="?android:attr/textAppearanceSmall" android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="?android:attr/textColorPrimary" /> android:textColor="?android:attr/textColorPrimary" />
<EditText <EditText
android:id="@+id/account_description" android:id="@+id/account_description"
android:inputType="textCapWords"
android:imeOptions="actionDone"
android:layout_height="wrap_content"
android:layout_width="match_parent" />
<TextView
android:id="@+id/account_name_label"
android:text="@string/account_setup_names_user_name_label"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_width="match_parent" android:layout_width="match_parent"
android:contentDescription="@string/account_setup_names_account_name_label"
android:inputType="textCapWords"
android:imeOptions="actionDone" />
<TextView
android:id="@+id/account_name_label"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:text="@string/account_setup_names_user_name_label"
android:textAppearance="?android:attr/textAppearanceSmall" android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="?android:attr/textColorPrimary" /> android:textColor="?android:attr/textColorPrimary" />
<EditText <EditText
android:id="@+id/account_name" android:id="@+id/account_name"
android:inputType="textPersonName"
android:imeOptions="actionDone"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_width="match_parent" /> android:layout_width="match_parent"
android:contentDescription="@string/account_setup_names_user_name_label"
android:inputType="textPersonName"
android:imeOptions="actionDone" />
<!-- TODO - quick placeholder - phone UX still TBD --> <!-- TODO - quick placeholder - phone UX still TBD -->
<Button <Button

View File

@ -18,6 +18,7 @@
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="@dimen/account_spinner_width" android:layout_width="@dimen/account_spinner_width"
android:layout_height="match_parent" android:layout_height="match_parent"
android:focusable="true"
style="@android:style/Widget.Holo.Spinner" style="@android:style/Widget.Holo.Spinner"
> >
<TextView <TextView

View File

@ -29,6 +29,7 @@
android:layout_height="24dip" android:layout_height="24dip"
android:layout_margin="6dip" android:layout_margin="6dip"
android:baselineAlignBottom="true" android:baselineAlignBottom="true"
android:contentDescription="@string/reply_action"
/> />
<View <View
android:layout_width="1dip" android:layout_width="1dip"

View File

@ -299,6 +299,11 @@
<!-- Mailbox list header for recent folders [CHAR LIMIT=30] --> <!-- Mailbox list header for recent folders [CHAR LIMIT=30] -->
<string name="mailbox_list_recent_mailboxes">Recent folders</string> <string name="mailbox_list_recent_mailboxes">Recent folders</string>
<!-- Announces the subject field for a message for users with accessibility requirements -->
<string name="message_subject_description">Subject</string>
<!-- Announces that a message has no sender or subject
to users with accessibility requirements -->
<string name="message_is_empty_description">No subject</string>
<!-- Appears at the bottom of list of messages; user selects to load more messages from that folder. --> <!-- Appears at the bottom of list of messages; user selects to load more messages from that folder. -->
<string name="message_list_load_more_messages_action">Load more messages</string> <string name="message_list_load_more_messages_action">Load more messages</string>
<!-- The number of messages that are currently selected for various operations such as <!-- The number of messages that are currently selected for various operations such as

View File

@ -40,6 +40,7 @@ import android.text.style.StyleSpan;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.view.MotionEvent; import android.view.MotionEvent;
import android.view.View; import android.view.View;
import android.view.accessibility.AccessibilityEvent;
/** /**
* This custom View is the list item for the MessageList activity, and serves two purposes: * This custom View is the list item for the MessageList activity, and serves two purposes:
@ -96,11 +97,14 @@ public class MessageListItem extends View {
private static Bitmap sStateForwarded; private static Bitmap sStateForwarded;
private static Bitmap sStateRepliedAndForwarded; private static Bitmap sStateRepliedAndForwarded;
private static String sSubjectSnippetDivider; private static String sSubjectSnippetDivider;
private static String sSubjectDescription;
private static String sSubjectEmptyDescription;
public String mSender; public String mSender;
public CharSequence mText; public CharSequence mText;
public CharSequence mSnippet; public CharSequence mSnippet;
public String mSubject; private String mSubject;
private String mSubjectAndDescription;
private StaticLayout mSubjectLayout; private StaticLayout mSubjectLayout;
public boolean mRead; public boolean mRead;
public long mTimestamp; public long mTimestamp;
@ -135,6 +139,8 @@ public class MessageListItem extends View {
mContext = context; mContext = context;
if (!sInit) { if (!sInit) {
Resources r = context.getResources(); Resources r = context.getResources();
sSubjectDescription = r.getString(R.string.message_subject_description).concat(", ");
sSubjectEmptyDescription = r.getString(R.string.message_is_empty_description);
sSubjectSnippetDivider = r.getString(R.string.message_list_subject_snippet_divider); sSubjectSnippetDivider = r.getString(R.string.message_list_subject_snippet_divider);
sTextSize = sTextSize =
r.getDimensionPixelSize(R.dimen.message_list_item_text_size); r.getDimensionPixelSize(R.dimen.message_list_item_text_size);
@ -175,6 +181,16 @@ public class MessageListItem extends View {
} }
} }
/**
* Sets message subject safely, ensuring the cache is invalidated.
*/
public void setSubject(String subject) {
if (!subject.equals(mSubject)) {
mSubject = subject;
mSubjectAndDescription = null;
}
}
/** /**
* Determine the mode of this view (WIDE or NORMAL) * Determine the mode of this view (WIDE or NORMAL)
* *
@ -457,4 +473,31 @@ public class MessageListItem extends View {
return handled; return handled;
} }
@Override
public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
CharSequence contentDescription = getContentDescription(mContext);
if (!TextUtils.isEmpty(contentDescription)) {
event.setClassName(getClass().getName());
event.setPackageName(getContext().getPackageName());
event.setEnabled(true);
event.setContentDescription(contentDescription);
return true;
}
return false;
}
/**
* Get message information to use for accessibility.
*/
private CharSequence getContentDescription(Context context) {
if (mSubjectAndDescription == null) {
if (!TextUtils.isEmpty(mSubject)) {
mSubjectAndDescription = sSubjectDescription + mSubject;
} else {
mSubjectAndDescription = sSubjectEmptyDescription;
}
}
return mSubjectAndDescription;
}
} }

View File

@ -199,7 +199,7 @@ import java.util.Set;
itemView.mTimestamp = cursor.getLong(COLUMN_DATE); itemView.mTimestamp = cursor.getLong(COLUMN_DATE);
itemView.mSender = cursor.getString(COLUMN_DISPLAY_NAME); itemView.mSender = cursor.getString(COLUMN_DISPLAY_NAME);
itemView.mSnippet = cursor.getString(COLUMN_SNIPPET); itemView.mSnippet = cursor.getString(COLUMN_SNIPPET);
itemView.mSubject = cursor.getString(COLUMN_SUBJECT); itemView.setSubject(cursor.getString(COLUMN_SUBJECT));
itemView.mSnippetLineCount = MessageListItem.NEEDS_LAYOUT; itemView.mSnippetLineCount = MessageListItem.NEEDS_LAYOUT;
itemView.mColorChipPaint = itemView.mColorChipPaint =
mShowColorChips ? mResourceHelper.getAccountColorPaint(accountId) : null; mShowColorChips ? mResourceHelper.getAccountColorPaint(accountId) : null;