provide content description for the player view to make show/hide controls accessible

PiperOrigin-RevId: 274148026
This commit is contained in:
bachinger 2019-10-11 12:36:49 +01:00 committed by Oliver Woodman
parent a268e1b63f
commit 674e92e1ee
4 changed files with 64 additions and 11 deletions

View File

@ -110,6 +110,7 @@
* Add `MediaPeriod.isLoading` to improve `Player.isLoading` state.
* Add support for ID3-in-EMSG in HLS streams
([spec](https://aomediacodec.github.io/av1-id3/)).
* Make show and hide player controls accessible for TalkBack in `PlayerView`.
### 2.10.5 (2019-09-20) ###

View File

@ -43,6 +43,7 @@ import com.google.android.exoplayer2.util.Util;
import java.util.Arrays;
import java.util.Formatter;
import java.util.Locale;
import java.util.concurrent.CopyOnWriteArrayList;
/**
* A view for controlling {@link Player} instances.
@ -231,6 +232,7 @@ public class PlayerControlView extends FrameLayout {
private static final int MAX_UPDATE_INTERVAL_MS = 1000;
private final ComponentListener componentListener;
private final CopyOnWriteArrayList<VisibilityListener> visibilityListeners;
private final View previousButton;
private final View nextButton;
private final View playButton;
@ -265,7 +267,6 @@ public class PlayerControlView extends FrameLayout {
@Nullable private Player player;
private com.google.android.exoplayer2.ControlDispatcher controlDispatcher;
@Nullable private VisibilityListener visibilityListener;
@Nullable private ProgressUpdateListener progressUpdateListener;
@Nullable private PlaybackPreparer playbackPreparer;
@ -335,6 +336,7 @@ public class PlayerControlView extends FrameLayout {
a.recycle();
}
}
visibilityListeners = new CopyOnWriteArrayList<>();
period = new Timeline.Period();
window = new Timeline.Window();
formatBuilder = new StringBuilder();
@ -510,13 +512,21 @@ public class PlayerControlView extends FrameLayout {
}
/**
* Sets the {@link VisibilityListener}.
* Adds a {@link VisibilityListener}.
*
* @param listener The listener to be notified about visibility changes, or null to remove the
* current listener.
* @param listener The listener to be notified about visibility changes.
*/
public void setVisibilityListener(@Nullable VisibilityListener listener) {
this.visibilityListener = listener;
public void addVisibilityListener(VisibilityListener listener) {
visibilityListeners.add(listener);
}
/**
* Removes a {@link VisibilityListener}.
*
* @param listener The listener to be removed.
*/
public void removeVisibilityListener(VisibilityListener listener) {
visibilityListeners.remove(listener);
}
/**
@ -697,7 +707,7 @@ public class PlayerControlView extends FrameLayout {
public void show() {
if (!isVisible()) {
setVisibility(VISIBLE);
if (visibilityListener != null) {
for (VisibilityListener visibilityListener : visibilityListeners) {
visibilityListener.onVisibilityChange(getVisibility());
}
updateAll();
@ -711,7 +721,7 @@ public class PlayerControlView extends FrameLayout {
public void hide() {
if (isVisible()) {
setVisibility(GONE);
if (visibilityListener != null) {
for (VisibilityListener visibilityListener : visibilityListeners) {
visibilityListener.onVisibilityChange(getVisibility());
}
removeCallbacks(updateProgressAction);

View File

@ -294,6 +294,7 @@ public class PlayerView extends FrameLayout implements AdsLoader.AdViewProvider
private Player player;
private boolean useController;
@Nullable private PlayerControlView.VisibilityListener controllerVisibilityListener;
private boolean useArtwork;
@Nullable private Drawable defaultArtwork;
private @ShowBuffering int showBuffering;
@ -483,6 +484,10 @@ public class PlayerView extends FrameLayout implements AdsLoader.AdViewProvider
this.controllerHideDuringAds = controllerHideDuringAds;
this.useController = useController && controller != null;
hideController();
updateContentDescription();
if (controller != null) {
controller.addVisibilityListener(/* listener= */ componentListener);
}
}
/**
@ -687,8 +692,9 @@ public class PlayerView extends FrameLayout implements AdsLoader.AdViewProvider
controller.setPlayer(player);
} else if (controller != null) {
controller.hide();
controller.setPlayer(null);
controller.setPlayer(/* player= */ null);
}
updateContentDescription();
}
/**
@ -880,6 +886,7 @@ public class PlayerView extends FrameLayout implements AdsLoader.AdViewProvider
public void setControllerHideOnTouch(boolean controllerHideOnTouch) {
Assertions.checkState(controller != null);
this.controllerHideOnTouch = controllerHideOnTouch;
updateContentDescription();
}
/**
@ -921,7 +928,16 @@ public class PlayerView extends FrameLayout implements AdsLoader.AdViewProvider
public void setControllerVisibilityListener(
@Nullable PlayerControlView.VisibilityListener listener) {
Assertions.checkState(controller != null);
controller.setVisibilityListener(listener);
if (this.controllerVisibilityListener == listener) {
return;
}
if (this.controllerVisibilityListener != null) {
controller.removeVisibilityListener(this.controllerVisibilityListener);
}
this.controllerVisibilityListener = listener;
if (listener != null) {
controller.addVisibilityListener(listener);
}
}
/**
@ -1359,6 +1375,20 @@ public class PlayerView extends FrameLayout implements AdsLoader.AdViewProvider
}
}
private void updateContentDescription() {
if (controller == null || !useController) {
setContentDescription(/* contentDescription= */ null);
} else if (controller.getVisibility() == View.VISIBLE) {
setContentDescription(
/* contentDescription= */ controllerHideOnTouch
? getResources().getString(R.string.exo_controls_hide)
: null);
} else {
setContentDescription(
/* contentDescription= */ getResources().getString(R.string.exo_controls_show));
}
}
@TargetApi(23)
private static void configureEditModeLogoV23(Resources resources, ImageView logo) {
logo.setImageDrawable(resources.getDrawable(R.drawable.exo_edit_mode_logo, null));
@ -1418,7 +1448,8 @@ public class PlayerView extends FrameLayout implements AdsLoader.AdViewProvider
TextOutput,
VideoListener,
OnLayoutChangeListener,
SingleTapListener {
SingleTapListener,
PlayerControlView.VisibilityListener {
// TextOutput implementation
@ -1513,5 +1544,12 @@ public class PlayerView extends FrameLayout implements AdsLoader.AdViewProvider
public boolean onSingleTapUp(MotionEvent e) {
return toggleControllerVisibility();
}
// PlayerControlView.VisibilityListener implementation
@Override
public void onVisibilityChange(int visibility) {
updateContentDescription();
}
}
}

View File

@ -14,6 +14,10 @@
limitations under the License.
-->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- Description for a media player view to indicate that tapping on the view shows the playback controls. [CHAR LIMIT=50] -->
<string name="exo_controls_show">Show player controls</string>
<!-- Description for a media player view to indicate that tapping on the view hides the playback controls [CHAR LIMIT=50] -->
<string name="exo_controls_hide">Hide player controls</string>
<!-- Description for a media control button that causes the previous track to be played. [CHAR LIMIT=30] -->
<string name="exo_controls_previous_description">Previous track</string>
<!-- Description for a media control button that causes the next track to be played. [CHAR LIMIT=30] -->