Bug 1315201: Override AS context menu a11y title. r=sebastian

MozReview-Commit-ID: HeX7hTpVtEP

--HG--
extra : rebase_source : afccf0e06bb8b1ac86ae7b0a47eda8f562bf9c55
This commit is contained in:
Michael Comella 2017-08-21 18:13:34 -07:00
Родитель 97b38a996c
Коммит cdf455e1bb
2 изменённых файлов: 69 добавлений и 4 удалений

Просмотреть файл

@ -11,7 +11,10 @@
android:orientation="vertical">
<!-- a11y: When the dialog first appears, the title is announced so there is no
need to allow refocusing the title. -->
need to allow refocusing the title.
Also, we override the a11y title of the dialog in code. If you change the text in id/url or id/title,
update the code! -->
<RelativeLayout
android:id="@+id/info_wrapper"
android:layout_width="match_parent"

Просмотреть файл

@ -6,6 +6,7 @@ package org.mozilla.gecko.activitystream.homepanel.menu;
import android.app.Activity;
import android.content.Context;
import android.net.Uri;
import android.support.design.widget.BottomSheetBehavior;
import android.support.design.widget.BottomSheetDialog;
import android.support.design.widget.NavigationView;
@ -16,6 +17,7 @@ import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.accessibility.AccessibilityEvent;
import android.widget.TextView;
import org.mozilla.gecko.R;
import org.mozilla.gecko.activitystream.ActivityStreamTelemetry;
@ -41,6 +43,9 @@ import java.net.URISyntaxException;
private final View content;
private final View activityView;
/** A reference, that represents the page domain, that allows a return value from an async task. */
private String[] pageDomainTextReference = new String[] { "" };
public BottomSheetContextMenu(final Context context,
final ActivityStreamTelemetry.Extras.Builder telemetryExtraBuilder,
final MenuMode mode,
@ -68,14 +73,15 @@ import java.net.URISyntaxException;
final String pageTitle = item.getTitle();
final String sheetPageTitle = !TextUtils.isEmpty(pageTitle) ? pageTitle : item.getUrl();
((TextView) content.findViewById(R.id.title)).setText(sheetPageTitle);
final TextView titleView = (TextView) content.findViewById(R.id.title);
titleView.setText(sheetPageTitle);
final TextView pageDomainView = (TextView) content.findViewById(R.id.url);
final URI itemURI;
try {
itemURI = new URI(item.getUrl());
final UpdatePageDomainAsyncTask updateDomainAsyncTask = new UpdatePageDomainAsyncTask(context, pageDomainView,
itemURI);
itemURI, pageDomainTextReference);
updateDomainAsyncTask.execute();
} catch (final URISyntaxException e) {
// Invalid URI: not much processing we can do. Like the async task, the page title view sets itself to the
@ -83,6 +89,8 @@ import java.net.URISyntaxException;
pageDomainView.setText("");
}
overrideInitialAccessibilityAnnouncement(pageDomainView, titleView, sheetPageTitle, item.getUrl());
// Copy layouted parameters from the Highlights / TopSites items to ensure consistency
final StreamOverridablePageIconLayout pageIconLayout =
(StreamOverridablePageIconLayout) content.findViewById(R.id.page_icon_layout);
@ -101,6 +109,56 @@ import java.net.URISyntaxException;
super.postInit();
}
/**
* Override the announcement made when the dialog first appears with Talkback enabled.
*
* By default, the dialog will find the first TextView (the page domain) and speak its contents as the initial
* announcement. However, in order to uniquely identify a site, we need both the page domain and the page title: we
* override the announcement with that content.
*
* Caveat: the page domain is retrieved asynchronously so this becomes tricky. In theory, we could block the UI
* thread for the page domain and with the current implementation, it'd be fine:
* - It's async only because the first time this method is called, it reads a file from disk.
* Otherwise, it's unnecessary.
* - This method is guaranteed to have already been called because about:home shows before this context menu can show
*
* But the implementation could change and it seemed incorrect to block showing this context menu for
* *all* users solely for a11y text that can be estimated.
*/
private void overrideInitialAccessibilityAnnouncement(final View pageDomainView, final View pageTitleView,
final String pageTitle, final String urlStr) {
final View.AccessibilityDelegate initialAnnouncementDelegate = new View.AccessibilityDelegate() {
@Override
public void onPopulateAccessibilityEvent(final View hostView, final AccessibilityEvent event) {
// The page domain is retrieved with an async operation and the return value is stored here.
final String shortenedHost = pageDomainTextReference[0];
final String finalHost;
if (!TextUtils.isEmpty(shortenedHost)) {
finalHost = shortenedHost;
} else if (TextUtils.isEmpty(urlStr)) {
// There's no url so we can't do any better.
finalHost = "";
} else {
// The async page domain isn't completed yet so we'll do a best approximation.
final Uri uri = Uri.parse(urlStr);
final String host = uri.getHost();
finalHost = !TextUtils.isEmpty(host) ? host : urlStr;
}
final String announcementText = finalHost + ", " + pageTitle;
event.getText().add(announcementText);
super.onPopulateAccessibilityEvent(hostView, event);
}
};
// The dialog finds the first available TextView and announces its text as the accessibility title. The
// pageDomainView is first but since the title is completed asynchronously, it may not have text yet, and
// may be an invalid first TextView, we have to set the listener on both the first and second TextViews.
pageDomainView.setAccessibilityDelegate(initialAnnouncementDelegate);
pageTitleView.setAccessibilityDelegate(initialAnnouncementDelegate);
}
@Override
public MenuItem getItemByID(int id) {
return navigationView.getMenu().findItem(id);
@ -169,10 +227,13 @@ import java.net.URISyntaxException;
/** Updates the given TextView's text to the page domain. */
private static class UpdatePageDomainAsyncTask extends URIUtils.GetFormattedDomainAsyncTask {
private final WeakReference<TextView> pageDomainViewWeakReference;
private final String[] pageDomainTextReference;
private UpdatePageDomainAsyncTask(final Context context, final TextView pageDomainView, final URI uri) {
private UpdatePageDomainAsyncTask(final Context context, final TextView pageDomainView, final URI uri,
final String[] pageDomainTextReference) {
super(context, uri, true, 0); // baseDomain.
this.pageDomainViewWeakReference = new WeakReference<>(pageDomainView);
this.pageDomainTextReference = pageDomainTextReference;
}
@Override
@ -195,6 +256,7 @@ import java.net.URISyntaxException;
updateText = !TextUtils.isEmpty(normalizedHost) ? normalizedHost : "";
}
pageDomainTextReference[0] = updateText;
pageDomainView.setText(updateText);
}
}