Commit 5be79d4f by bachinger Committed by Oliver Woodman

Media session extension to connect ExoPlayer with the MediaSession of the

framework.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=162245883
parent 387720d1
Showing with 3110 additions and 63 deletions
...@@ -28,6 +28,7 @@ include modulePrefix + 'extension-ffmpeg' ...@@ -28,6 +28,7 @@ include modulePrefix + 'extension-ffmpeg'
include modulePrefix + 'extension-flac' include modulePrefix + 'extension-flac'
include modulePrefix + 'extension-gvr' include modulePrefix + 'extension-gvr'
include modulePrefix + 'extension-ima' include modulePrefix + 'extension-ima'
include modulePrefix + 'extension-mediasession'
include modulePrefix + 'extension-okhttp' include modulePrefix + 'extension-okhttp'
include modulePrefix + 'extension-opus' include modulePrefix + 'extension-opus'
include modulePrefix + 'extension-vp9' include modulePrefix + 'extension-vp9'
...@@ -44,6 +45,7 @@ project(modulePrefix + 'extension-ffmpeg').projectDir = new File(rootDir, 'exten ...@@ -44,6 +45,7 @@ project(modulePrefix + 'extension-ffmpeg').projectDir = new File(rootDir, 'exten
project(modulePrefix + 'extension-flac').projectDir = new File(rootDir, 'extensions/flac') project(modulePrefix + 'extension-flac').projectDir = new File(rootDir, 'extensions/flac')
project(modulePrefix + 'extension-gvr').projectDir = new File(rootDir, 'extensions/gvr') project(modulePrefix + 'extension-gvr').projectDir = new File(rootDir, 'extensions/gvr')
project(modulePrefix + 'extension-ima').projectDir = new File(rootDir, 'extensions/ima') project(modulePrefix + 'extension-ima').projectDir = new File(rootDir, 'extensions/ima')
project(modulePrefix + 'extension-mediasession').projectDir = new File(rootDir, 'extensions/mediasession')
project(modulePrefix + 'extension-okhttp').projectDir = new File(rootDir, 'extensions/okhttp') project(modulePrefix + 'extension-okhttp').projectDir = new File(rootDir, 'extensions/okhttp')
project(modulePrefix + 'extension-opus').projectDir = new File(rootDir, 'extensions/opus') project(modulePrefix + 'extension-opus').projectDir = new File(rootDir, 'extensions/opus')
project(modulePrefix + 'extension-vp9').projectDir = new File(rootDir, 'extensions/vp9') project(modulePrefix + 'extension-vp9').projectDir = new File(rootDir, 'extensions/vp9')
......
# ExoPlayer MediaSession Extension #
## Description ##
The MediaSession Extension mediates between an ExoPlayer instance and a
[MediaSession][]. It automatically retrieves and implements playback actions
and syncs the player state with the state of the media session. The behaviour
can be extended to support other playback and custom actions.
[MediaSession]: https://developer.android.com/reference/android/support/v4/media/session/MediaSessionCompat.html
## Getting the extension ##
The easiest way to use the extension is to add it as a gradle dependency:
```gradle
compile 'com.google.android.exoplayer:extension-mediasession:rX.X.X'
```
where `rX.X.X` is the version, which must match the version of the ExoPlayer
library being used.
Alternatively, you can clone the ExoPlayer repository and depend on the module
locally. Instructions for doing this can be found in ExoPlayer's
[top level README][].
[top level README]: https://github.com/google/ExoPlayer/blob/release-v2/README.md
// Copyright (C) 2017 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
apply from: '../../constants.gradle'
apply plugin: 'com.android.library'
android {
compileSdkVersion project.ext.compileSdkVersion
buildToolsVersion project.ext.buildToolsVersion
defaultConfig {
minSdkVersion project.ext.minSdkVersion
targetSdkVersion project.ext.targetSdkVersion
}
}
dependencies {
compile project(':library-core')
compile 'com.android.support:support-media-compat:' + supportLibraryVersion
compile 'com.android.support:appcompat-v7:' + supportLibraryVersion
}
ext {
javadocTitle = 'Media session extension'
}
apply from: '../../javadoc_library.gradle'
ext {
releaseArtifact = 'extension-mediasession'
releaseDescription = 'Media session extension for ExoPlayer.'
}
apply from: '../../publish.gradle'
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2017 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<manifest package="com.google.android.exoplayer2.ext.mediasession"/>
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.android.exoplayer2.ext.mediasession;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.ResultReceiver;
import android.os.SystemClock;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.media.MediaDescriptionCompat;
import android.support.v4.media.MediaMetadataCompat;
import android.support.v4.media.RatingCompat;
import android.support.v4.media.session.MediaControllerCompat;
import android.support.v4.media.session.MediaSessionCompat;
import android.support.v4.media.session.PlaybackStateCompat;
import android.util.Pair;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.ExoPlaybackException;
import com.google.android.exoplayer2.ExoPlayer;
import com.google.android.exoplayer2.ExoPlayerLibraryInfo;
import com.google.android.exoplayer2.PlaybackParameters;
import com.google.android.exoplayer2.SimpleExoPlayer;
import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.source.TrackGroupArray;
import com.google.android.exoplayer2.trackselection.TrackSelectionArray;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Mediates between a {@link MediaSessionCompat} and an {@link SimpleExoPlayer} instance set with
* {@link #setPlayer(SimpleExoPlayer)}.
* <p>
* By default the {@code MediaSessionConnector} listens for {@link #DEFAULT_PLAYBACK_ACTIONS} sent
* by a media controller and realizes these actions by calling appropriate ExoPlayer methods.
* Further, the state of ExoPlayer will be synced automatically with the {@link PlaybackStateCompat}
* of the media session to broadcast state transitions to clients. You can optionally extend this
* behaviour by providing various collaborators.
* <p>
* Media actions to initiate media playback ({@code PlaybackStateCompat#ACTION_PREPARE_*} and
* {@code PlaybackStateCompat#ACTION_PLAY_*} need to be handled by a {@link PlaybackPreparer} which
* build a {@link com.google.android.exoplayer2.source.MediaSource} to prepare ExoPlayer. Deploy
* your preparer by calling {@link #setPlaybackPreparer(PlaybackPreparer)}.
* <p>
* To support a media session queue and navigation within this queue, you can set a
* {@link QueueNavigator} to maintain the queue yourself and implement queue navigation commands
* (like 'skip to next') sent by controllers. It's recommended to use the
* {@link TimelineQueueNavigator} to allow users navigating the windows of the ExoPlayer timeline.
* <p>
* If you want to allow media controllers to manipulate the queue, implement a {@link QueueEditor}
* and deploy it with {@link #setQueueEditor(QueueEditor)}.
* <p>
* Set an {@link ErrorMessageProvider} to provide an error code and a human readable error message
* to be broadcast to controllers.
*/
public final class MediaSessionConnector {
static {
ExoPlayerLibraryInfo.registerModule("goog.exo.mediasession");
}
/**
* Actions that are published to the media session by default
* ({@code PlaybackStateCompat.ACTION_PLAY_PAUSE}, {@code PlaybackStateCompat.ACTION_PLAY},
* {@code PlaybackStateCompat.ACTION_PAUSE}, {@code PlaybackStateCompat.ACTION_FAST_FORWARD},
* {@code PlaybackStateCompat.ACTION_REWIND}).
*/
public static final long DEFAULT_PLAYBACK_ACTIONS = PlaybackStateCompat.ACTION_PLAY_PAUSE
| PlaybackStateCompat.ACTION_PLAY | PlaybackStateCompat.ACTION_PAUSE
| PlaybackStateCompat.ACTION_FAST_FORWARD | PlaybackStateCompat.ACTION_REWIND;
public static final String EXTRAS_PITCH = "EXO_PITCH";
public static final long DEFAULT_FAST_FORWARD_MS = 15000;
public static final long DEFAULT_REWIND_MS = 5000;
/**
* Interface of components taking responsibility of a set of media session playback actions
* ({@code PlaybackStateCompat#ACTION_*}).
*/
public interface PlaybackActionSupport {
/**
* Returns the bit mask of the playback actions supported by this component.
*/
long getSupportedPlaybackActions();
}
/**
* Interface to which media controller commands regarding preparing playback for a given media
* clip are delegated to.
* <p>
* Normally preparing playback includes preparing the player with a
* {@link com.google.android.exoplayer2.source.MediaSource} and setting up the media session queue
* with a corresponding list of queue items.
*/
public interface PlaybackPreparer extends PlaybackActionSupport {
/**
* See {@link MediaSessionCompat.Callback#onPrepare()}.
*/
void onPrepare(ExoPlayer player);
/**
* See {@link MediaSessionCompat.Callback#onPrepareFromMediaId(String, Bundle)}.
*/
void onPrepareFromMediaId(ExoPlayer player, String mediaId, Bundle extras);
/**
* See {@link MediaSessionCompat.Callback#onPrepareFromSearch(String, Bundle)}.
*/
void onPrepareFromSearch(ExoPlayer player, String query, Bundle extras);
/**
* See {@link MediaSessionCompat.Callback#onPrepareFromUri(Uri, Bundle)}.
*/
void onPrepareFromUri(ExoPlayer player, Uri uri, Bundle extras);
/**
* See {@link MediaSessionCompat.Callback#onCommand(String, Bundle, ResultReceiver)}.
*/
void onCommand(ExoPlayer player, String command, Bundle extras, ResultReceiver cb);
}
/**
* Navigator to handle queue navigation commands and maintain the media session queue with
* {#link MediaSessionCompat#setQueue(List)} to provide the active queue item to the connector.
*/
public interface QueueNavigator extends PlaybackActionSupport {
/**
* Called when the timeline of the player has changed.
*
* @param player The player of which the timeline has changed.
*/
void onTimelineChanged(ExoPlayer player);
/**
* Called when the current window index changed.
*
* @param player The player of which the current window index of the timeline has changed.
*/
void onCurrentWindowIndexChanged(ExoPlayer player);
/**
* Gets the id of the currently active queue item or
* {@link MediaSessionCompat.QueueItem#UNKNOWN_ID} if the active item is unknown.
* <p>
* To let the connector publish metadata for the active queue item, the queue item with the
* returned id must be available in the list of items returned by
* {@link MediaControllerCompat#getQueue()}.
*
* @param player The player connected to the media session.
* @return The id of the active queue item.
*/
long getActiveQueueItemId(@Nullable ExoPlayer player);
/**
* See {@link MediaSessionCompat.Callback#onSkipToPrevious()).
*/
void onSkipToPrevious(ExoPlayer player);
/**
* See {@link MediaSessionCompat.Callback#onSkipToQueueItem(long)}.
*/
void onSkipToQueueItem(ExoPlayer player, long id);
/**
* See {@link MediaSessionCompat.Callback#onSkipToNext()}.
*/
void onSkipToNext(ExoPlayer player);
/**
* See {@link MediaSessionCompat.Callback#onSetShuffleModeEnabled(boolean)}.
*/
void onSetShuffleModeEnabled(ExoPlayer player, boolean enabled);
}
/**
* Editor to manipulate the queue.
*/
public interface QueueEditor extends PlaybackActionSupport {
/**
* See {@link MediaSessionCompat.Callback#onAddQueueItem(MediaDescriptionCompat description)}.
*/
void onAddQueueItem(ExoPlayer player, MediaDescriptionCompat description);
/**
* See {@link MediaSessionCompat.Callback#onAddQueueItem(MediaDescriptionCompat description,
* int index)}.
*/
void onAddQueueItem(ExoPlayer player, MediaDescriptionCompat description, int index);
/**
* See {@link MediaSessionCompat.Callback#onRemoveQueueItem(MediaDescriptionCompat
* description)}.
*/
void onRemoveQueueItem(ExoPlayer player, MediaDescriptionCompat description);
/**
* See {@link MediaSessionCompat.Callback#onRemoveQueueItemAt(int index)).
*/
void onRemoveQueueItemAt(ExoPlayer player, int index);
/**
* See {@link MediaSessionCompat.Callback#onSetRating(RatingCompat)}.
*/
void onSetRating(ExoPlayer player, RatingCompat rating);
}
/**
* Provides a {@link PlaybackStateCompat.CustomAction} to be published and handles the action when
* sent by a media controller.
*/
public interface CustomActionProvider {
/**
* Called when a custom action provided by this provider is sent to the media session.
*
* @param player The player for which to process the custom action.
* @param action The name of the action which was sent by a media controller.
* @param extras Optional extras sent by a media controller.
*/
void onCustomAction(SimpleExoPlayer player, String action, Bundle extras);
/**
* Returns a {@link PlaybackStateCompat.CustomAction} which will be published to the
* media session by the connector or {@code null} if this action should not be published at the
* given player state.
*
* @param player The player for which to provide actions.
* @return The custom action to be included in the session playback state or {@code null}.
*/
PlaybackStateCompat.CustomAction getCustomAction(SimpleExoPlayer player);
}
/**
* Provides an user readable error code and a message for {@link ExoPlaybackException}s.
*/
public interface ErrorMessageProvider {
/**
* Returns a pair of an error code and a user readable error message for a given
* {@link ExoPlaybackException}.
*/
Pair<Integer, String> getErrorMessage(ExoPlaybackException playbackException);
}
/**
* The wrapped {@link MediaSessionCompat}.
*/
public final MediaSessionCompat mediaSession;
private final MediaControllerCompat mediaController;
private final Handler handler;
private final boolean doMaintainMetadata;
private final ExoPlayerEventListener exoPlayerEventListener;
private final MediaSessionCallback mediaSessionCallback;
private final CustomActionProvider[] customActionProviders;
private SimpleExoPlayer player;
private int currentWindowIndex;
private long playbackActions;
private long fastForwardIncrementMs;
private long rewindIncrementMs;
private Map<String, CustomActionProvider> customActionMap;
private ErrorMessageProvider errorMessageProvider;
private PlaybackPreparer playbackPreparer;
private QueueNavigator queueNavigator;
private QueueEditor queueEditor;
private ExoPlaybackException playbackException;
/**
* Creates a {@code MediaSessionConnector}. This is equivalent to calling
* {@code #MediaSessionConnector(mediaSession, true)}.
* <p>
* Constructing the {@link MediaSessionConnector} needs to be done on the same thread as
* constructing the player instance.
*
* @param mediaSession The {@link MediaSessionCompat} to connect to.
*/
public MediaSessionConnector(MediaSessionCompat mediaSession) {
this(mediaSession, true);
}
/**
* Creates a {@code MediaSessionConnector} with {@link CustomActionProvider}s.
* <p>
* The order in which the {@link CustomActionProvider}s are passed to the constructor determines
* the order of the actions published with the playback state of the session.
* <p>
* If you choose to pass {@code false} for {@code doMaintainMetadata} you need to maintain the
* metadata of the media session yourself (provide at least the duration to allow clients to show
* a progress bar).
* <p>
* Constructing the {@link MediaSessionConnector} needs to be done on the same thread as
* constructing the player instance.
*
* @param mediaSession The {@link MediaSessionCompat} to connect to.
* @param doMaintainMetadata Sets whether the connector should maintain the metadata of the
* session.
* @param customActionProviders {@link CustomActionProvider}s to publish and handle custom
* actions.
*/
public MediaSessionConnector(MediaSessionCompat mediaSession, boolean doMaintainMetadata,
CustomActionProvider... customActionProviders) {
this.mediaSession = mediaSession;
this.handler = new Handler(Looper.myLooper() != null ? Looper.myLooper()
: Looper.getMainLooper());
this.doMaintainMetadata = doMaintainMetadata;
this.customActionProviders = customActionProviders != null ? customActionProviders
: new CustomActionProvider[0];
mediaSession.setFlags(MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS
| MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS);
mediaController = mediaSession.getController();
mediaSessionCallback = new MediaSessionCallback();
exoPlayerEventListener = new ExoPlayerEventListener();
playbackActions = DEFAULT_PLAYBACK_ACTIONS;
customActionMap = Collections.emptyMap();
fastForwardIncrementMs = DEFAULT_FAST_FORWARD_MS;
rewindIncrementMs = DEFAULT_REWIND_MS;
}
/**
* Sets the player to which media commands sent by a media controller are delegated.
* <p>
* The media session callback is set if the {@code player} is not {@code null} and the callback is
* removed if the {@code player} is {@code null}.
*
* @param player The player to be connected to the {@code MediaSession}.
*/
public void setPlayer(SimpleExoPlayer player) {
if (this.player != null) {
this.player.removeListener(exoPlayerEventListener);
mediaSession.setCallback(null);
}
this.player = player;
if (player != null) {
mediaSession.setCallback(mediaSessionCallback, handler);
player.addListener(exoPlayerEventListener);
}
updateMediaSessionPlaybackState();
updateMediaSessionMetadata();
}
/**
* Sets the fast forward increment in milliseconds. A positive value will cause the
* {@link PlaybackStateCompat#ACTION_FAST_FORWARD} playback action to be added. A zero or a
* negative value will cause it to be removed.
*
* @param fastForwardIncrementMs The fast forward increment in milliseconds.
*/
public void setFastForwardIncrementMs(long fastForwardIncrementMs) {
this.fastForwardIncrementMs = fastForwardIncrementMs;
if (fastForwardIncrementMs > 0) {
addPlaybackActions(PlaybackStateCompat.ACTION_FAST_FORWARD);
} else {
removePlaybackActions(PlaybackStateCompat.ACTION_FAST_FORWARD);
}
}
/**
* Sets the rewind increment in milliseconds. A positive value will cause the
* {@link PlaybackStateCompat#ACTION_REWIND} playback action to be added. A zero or a
* negative value will cause it to be removed.
*
* @param rewindIncrementMs The rewind increment in milliseconds.
*/
public void setRewindIncrementMs(long rewindIncrementMs) {
this.rewindIncrementMs = rewindIncrementMs;
if (rewindIncrementMs > 0) {
addPlaybackActions(PlaybackStateCompat.ACTION_REWIND);
} else {
removePlaybackActions(PlaybackStateCompat.ACTION_REWIND);
}
}
/**
* Adds playback actions. The playback actions that are enabled by default are those in
* {@link MediaSessionConnector#DEFAULT_PLAYBACK_ACTIONS}. See {@link PlaybackStateCompat} for
* available playback action constants.
*
* @param playbackActions The playback actions to add.
*/
public void addPlaybackActions(long playbackActions) {
this.playbackActions |= playbackActions;
}
/**
* Removes playback actions. The playback actions that are enabled by default are those in
* {@link MediaSessionConnector#DEFAULT_PLAYBACK_ACTIONS}.
*
* @param playbackActions The playback actions to remove.
*/
public void removePlaybackActions(long playbackActions) {
this.playbackActions &= ~playbackActions;
}
/**
* Sets the playback actions. The playback actions that are enabled by default are overridden.
*
* @param playbackActions The playback actions to publish.
*/
public void setPlaybackActions(long playbackActions) {
this.playbackActions = playbackActions;
}
/**
* Sets the optional {@link ErrorMessageProvider}.
*
* @param errorMessageProvider The {@link ErrorMessageProvider}.
*/
public void setErrorMessageProvider(ErrorMessageProvider errorMessageProvider) {
this.errorMessageProvider = errorMessageProvider;
}
/**
* Sets the {@link QueueNavigator} to handle queue navigation for the media actions
* {@code ACTION_SKIP_TO_NEXT}, {@code ACTION_SKIP_TO_PREVIOUS},
* {@code ACTION_SKIP_TO_QUEUE_ITEM} and {@code ACTION_SET_SHUFFLE_MODE_ENABLED}.
*
* @param queueNavigator The navigator to handle queue navigation.
*/
public void setQueueNavigator(QueueNavigator queueNavigator) {
if (this.queueNavigator != null) {
removePlaybackActions(this.queueNavigator.getSupportedPlaybackActions());
}
this.queueNavigator = queueNavigator;
if (queueNavigator != null) {
addPlaybackActions(queueNavigator.getSupportedPlaybackActions());
}
}
/**
* Sets the queue editor to handle commands to manipulate the queue sent by a media controller.
*
* @param queueEditor The editor to handle queue manipulation actions.
*/
public void setQueueEditor(QueueEditor queueEditor) {
if (this.queueEditor != null) {
removePlaybackActions(this.queueEditor.getSupportedPlaybackActions());
}
this.queueEditor = queueEditor;
if (queueEditor != null) {
addPlaybackActions(queueEditor.getSupportedPlaybackActions());
}
}
/**
* Sets the {@link PlaybackPreparer} to which preparation commands sent by a media
* controller are delegated.
* <p>
* Required to work properly with Android Auto which requires
* {@link PlaybackStateCompat#ACTION_PREPARE_FROM_MEDIA_ID}.
*
* @param playbackPreparer The preparer to delegate to.
*/
public void setPlaybackPreparer(PlaybackPreparer playbackPreparer) {
if (this.playbackPreparer != null) {
removePlaybackActions(this.playbackPreparer.getSupportedPlaybackActions());
}
this.playbackPreparer = playbackPreparer;
if (playbackPreparer != null) {
addPlaybackActions(playbackPreparer.getSupportedPlaybackActions());
}
}
private void updateMediaSessionPlaybackState() {
PlaybackStateCompat.Builder builder = new PlaybackStateCompat.Builder();
if (player == null) {
builder.setActions(0).setState(PlaybackStateCompat.STATE_NONE, 0, 0, 0);
mediaSession.setPlaybackState(builder.build());
return;
}
Map<String, CustomActionProvider> currentActions = new HashMap<>();
for (CustomActionProvider customActionProvider : customActionProviders) {
PlaybackStateCompat.CustomAction customAction = customActionProvider
.getCustomAction(player);
if (customAction != null) {
currentActions.put(customAction.getAction(), customActionProvider);
builder.addCustomAction(customAction);
}
}
customActionMap = Collections.unmodifiableMap(currentActions);
int sessionPlaybackState = playbackException != null ? PlaybackStateCompat.STATE_ERROR
: mapPlaybackState(player.getPlaybackState(), player.getPlayWhenReady());
if (playbackException != null) {
if (errorMessageProvider != null) {
Pair<Integer, String> message = errorMessageProvider.getErrorMessage(playbackException);
builder.setErrorMessage(message.first, message.second);
}
if (player.getPlaybackState() != ExoPlayer.STATE_IDLE) {
playbackException = null;
}
}
long activeQueueItemId = queueNavigator != null ? queueNavigator.getActiveQueueItemId(player)
: MediaSessionCompat.QueueItem.UNKNOWN_ID;
updatePlaybackActions(activeQueueItemId);
Bundle extras = new Bundle();
extras.putFloat(EXTRAS_PITCH, player.getPlaybackParameters().pitch);
builder.setActions(playbackActions)
.setActiveQueueItemId(activeQueueItemId)
.setBufferedPosition(player.getBufferedPosition())
.setState(sessionPlaybackState, player.getCurrentPosition(),
player.getPlaybackParameters().speed, SystemClock.elapsedRealtime())
.setExtras(extras);
mediaSession.setPlaybackState(builder.build());
}
private void updatePlaybackActions(long activeQueueItemId) {
List<MediaSessionCompat.QueueItem> queue = mediaController.getQueue();
if (queue == null || queue.size() < 2) {
removePlaybackActions(PlaybackStateCompat.ACTION_SKIP_TO_NEXT
| PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS);
} else if (player.getRepeatMode() != ExoPlayer.REPEAT_MODE_OFF) {
addPlaybackActions(PlaybackStateCompat.ACTION_SKIP_TO_NEXT
| PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS);
} else if (activeQueueItemId == queue.get(0).getQueueId()) {
removePlaybackActions(PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS);
addPlaybackActions(PlaybackStateCompat.ACTION_SKIP_TO_NEXT);
} else if (activeQueueItemId == queue.get(queue.size() - 1).getQueueId()) {
removePlaybackActions(PlaybackStateCompat.ACTION_SKIP_TO_NEXT);
addPlaybackActions(PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS);
} else {
addPlaybackActions(PlaybackStateCompat.ACTION_SKIP_TO_NEXT
| PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS);
}
}
private void updateMediaSessionMetadata() {
if (doMaintainMetadata) {
MediaMetadataCompat.Builder builder = new MediaMetadataCompat.Builder();
if (player != null && player.isPlayingAd()) {
builder.putLong(MediaMetadataCompat.METADATA_KEY_ADVERTISEMENT, 1);
}
builder.putLong(MediaMetadataCompat.METADATA_KEY_DURATION, player == null ? 0
: player.getDuration() == C.TIME_UNSET ? -1 : player.getDuration());
if (queueNavigator != null) {
long activeQueueItemId = queueNavigator.getActiveQueueItemId(player);
List<MediaSessionCompat.QueueItem> queue = mediaController.getQueue();
for (int i = 0; queue != null && i < queue.size(); i++) {
MediaSessionCompat.QueueItem queueItem = queue.get(i);
if (queueItem.getQueueId() == activeQueueItemId) {
MediaDescriptionCompat description = queueItem.getDescription();
if (description.getTitle() != null) {
builder.putString(MediaMetadataCompat.METADATA_KEY_DISPLAY_TITLE,
String.valueOf(description.getTitle()));
}
if (description.getSubtitle() != null) {
builder.putString(MediaMetadataCompat.METADATA_KEY_DISPLAY_SUBTITLE,
String.valueOf(description.getSubtitle()));
}
if (description.getDescription() != null) {
builder.putString(MediaMetadataCompat.METADATA_KEY_DISPLAY_DESCRIPTION,
String.valueOf(description.getDescription()));
}
if (description.getIconBitmap() != null) {
builder.putBitmap(MediaMetadataCompat.METADATA_KEY_DISPLAY_ICON,
description.getIconBitmap());
}
if (description.getIconUri() != null) {
builder.putString(MediaMetadataCompat.METADATA_KEY_DISPLAY_ICON_URI,
String.valueOf(description.getIconUri()));
}
if (description.getMediaId() != null) {
builder.putString(MediaMetadataCompat.METADATA_KEY_MEDIA_ID,
String.valueOf(description.getMediaId()));
}
if (description.getMediaUri() != null) {
builder.putString(MediaMetadataCompat.METADATA_KEY_MEDIA_URI,
String.valueOf(description.getMediaUri()));
}
break;
}
}
}
mediaSession.setMetadata(builder.build());
}
}
private int mapPlaybackState(int exoPlayerPlaybackState, boolean playWhenReady) {
switch (exoPlayerPlaybackState) {
case ExoPlayer.STATE_BUFFERING:
return PlaybackStateCompat.STATE_BUFFERING;
case ExoPlayer.STATE_READY:
return playWhenReady ? PlaybackStateCompat.STATE_PLAYING : PlaybackStateCompat.STATE_PAUSED;
case ExoPlayer.STATE_ENDED:
return PlaybackStateCompat.STATE_PAUSED;
default:
return PlaybackStateCompat.STATE_NONE;
}
}
private boolean isActionPublished(long action) {
return (playbackActions & action) != 0;
}
private boolean canDispatchToQueueNavigator(long action) {
return queueNavigator != null && isActionPublished(action);
}
private boolean canDispatchToPlaybackPreparer(long action) {
return playbackPreparer != null && isActionPublished(action);
}
private class ExoPlayerEventListener implements ExoPlayer.EventListener {
@Override
public void onTimelineChanged(Timeline timeline, Object manifest) {
if (queueNavigator != null) {
queueNavigator.onTimelineChanged(player);
}
currentWindowIndex = player.getCurrentWindowIndex();
updateMediaSessionMetadata();
}
@Override
public void onTracksChanged(TrackGroupArray trackGroups, TrackSelectionArray trackSelections) {
// Do nothing.
}
@Override
public void onLoadingChanged(boolean isLoading) {
// Do nothing.
}
@Override
public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {
updateMediaSessionPlaybackState();
}
@Override
public void onRepeatModeChanged(@ExoPlayer.RepeatMode int repeatMode) {
mediaSession.setRepeatMode(repeatMode == ExoPlayer.REPEAT_MODE_ONE
? PlaybackStateCompat.REPEAT_MODE_ONE : repeatMode == ExoPlayer.REPEAT_MODE_ALL
? PlaybackStateCompat.REPEAT_MODE_ALL : PlaybackStateCompat.REPEAT_MODE_NONE);
updateMediaSessionPlaybackState();
}
@Override
public void onPlayerError(ExoPlaybackException error) {
playbackException = error;
updateMediaSessionPlaybackState();
}
@Override
public void onPositionDiscontinuity() {
if (currentWindowIndex != player.getCurrentWindowIndex()) {
if (queueNavigator != null) {
queueNavigator.onCurrentWindowIndexChanged(player);
}
updateMediaSessionMetadata();
currentWindowIndex = player.getCurrentWindowIndex();
}
updateMediaSessionPlaybackState();
}
@Override
public void onPlaybackParametersChanged(PlaybackParameters playbackParameters) {
updateMediaSessionPlaybackState();
}
}
private class MediaSessionCallback extends MediaSessionCompat.Callback {
@Override
public void onPlay() {
player.setPlayWhenReady(true);
}
@Override
public void onPause() {
player.setPlayWhenReady(false);
}
@Override
public void onSeekTo(long position) {
long duration = player.getDuration();
if (duration != C.TIME_UNSET) {
position = Math.min(position, duration);
}
player.seekTo(Math.max(position, 0));
}
@Override
public void onFastForward() {
if (fastForwardIncrementMs <= 0) {
return;
}
onSeekTo(player.getCurrentPosition() + fastForwardIncrementMs);
}
@Override
public void onRewind() {
if (rewindIncrementMs <= 0) {
return;
}
onSeekTo(player.getCurrentPosition() - rewindIncrementMs);
}
@Override
public void onSkipToNext() {
if (canDispatchToQueueNavigator(PlaybackStateCompat.ACTION_SKIP_TO_NEXT)) {
queueNavigator.onSkipToNext(player);
}
}
@Override
public void onSkipToPrevious() {
if (canDispatchToQueueNavigator(PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS)) {
queueNavigator.onSkipToPrevious(player);
}
}
@Override
public void onSkipToQueueItem(long id) {
if (canDispatchToQueueNavigator(PlaybackStateCompat.ACTION_SKIP_TO_QUEUE_ITEM)) {
queueNavigator.onSkipToQueueItem(player, id);
}
}
@Override
public void onStop() {
if (isActionPublished(PlaybackStateCompat.ACTION_STOP)) {
player.stop();
}
}
@Override
public void onSetRepeatMode(int repeatMode) {
// implemented as custom action
}
@Override
public void onCustomAction(@NonNull String action, @Nullable Bundle extras) {
Map<String, CustomActionProvider> actionMap = customActionMap;
if (actionMap.containsKey(action)) {
actionMap.get(action).onCustomAction(player, action, extras);
updateMediaSessionPlaybackState();
}
}
@Override
public void onCommand(String command, Bundle extras, ResultReceiver cb) {
if (playbackPreparer != null) {
playbackPreparer.onCommand(player, command, extras, cb);
}
}
@Override
public void onPrepare() {
if (canDispatchToPlaybackPreparer(PlaybackStateCompat.ACTION_PREPARE)) {
player.stop();
player.setPlayWhenReady(false);
playbackPreparer.onPrepare(player);
}
}
@Override
public void onPrepareFromMediaId(String mediaId, Bundle extras) {
if (canDispatchToPlaybackPreparer(PlaybackStateCompat.ACTION_PREPARE_FROM_MEDIA_ID)) {
player.stop();
player.setPlayWhenReady(false);
playbackPreparer.onPrepareFromMediaId(player, mediaId, extras);
}
}
@Override
public void onPrepareFromSearch(String query, Bundle extras) {
if (canDispatchToPlaybackPreparer(PlaybackStateCompat.ACTION_PREPARE_FROM_SEARCH)) {
player.stop();
player.setPlayWhenReady(false);
playbackPreparer.onPrepareFromSearch(player, query, extras);
}
}
@Override
public void onPrepareFromUri(Uri uri, Bundle extras) {
if (canDispatchToPlaybackPreparer(PlaybackStateCompat.ACTION_PREPARE_FROM_URI)) {
player.stop();
player.setPlayWhenReady(false);
playbackPreparer.onPrepareFromUri(player, uri, extras);
}
}
@Override
public void onPlayFromMediaId(String mediaId, Bundle extras) {
if (canDispatchToPlaybackPreparer(PlaybackStateCompat.ACTION_PLAY_FROM_MEDIA_ID)) {
player.stop();
player.setPlayWhenReady(true);
playbackPreparer.onPrepareFromMediaId(player, mediaId, extras);
}
}
@Override
public void onPlayFromSearch(String query, Bundle extras) {
if (canDispatchToPlaybackPreparer(PlaybackStateCompat.ACTION_PLAY_FROM_SEARCH)) {
player.stop();
player.setPlayWhenReady(true);
playbackPreparer.onPrepareFromSearch(player, query, extras);
}
}
@Override
public void onPlayFromUri(Uri uri, Bundle extras) {
if (canDispatchToPlaybackPreparer(PlaybackStateCompat.ACTION_PLAY_FROM_URI)) {
player.stop();
player.setPlayWhenReady(true);
playbackPreparer.onPrepareFromUri(player, uri, extras);
}
}
@Override
public void onSetShuffleModeEnabled(boolean enabled) {
if (canDispatchToQueueNavigator(PlaybackStateCompat.ACTION_SET_SHUFFLE_MODE_ENABLED)) {
queueNavigator.onSetShuffleModeEnabled(player, enabled);
}
}
@Override
public void onAddQueueItem(MediaDescriptionCompat description) {
if (queueEditor != null) {
queueEditor.onAddQueueItem(player, description);
}
}
@Override
public void onAddQueueItem(MediaDescriptionCompat description, int index) {
if (queueEditor != null) {
queueEditor.onAddQueueItem(player, description, index);
}
}
@Override
public void onRemoveQueueItem(MediaDescriptionCompat description) {
if (queueEditor != null) {
queueEditor.onRemoveQueueItem(player, description);
}
}
@Override
public void onRemoveQueueItemAt(int index) {
if (queueEditor != null) {
queueEditor.onRemoveQueueItemAt(player, index);
}
}
@Override
public void onSetRating(RatingCompat rating) {
if (queueEditor != null && isActionPublished(PlaybackStateCompat.ACTION_SET_RATING)) {
queueEditor.onSetRating(player, rating);
}
}
}
}
package com.google.android.exoplayer2.ext.mediasession;
/*
* Copyright (c) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import android.content.Context;
import android.os.Bundle;
import android.support.v4.media.session.PlaybackStateCompat;
import com.google.android.exoplayer2.ExoPlayer;
import com.google.android.exoplayer2.SimpleExoPlayer;
import com.google.android.exoplayer2.util.RepeatModeUtil;
/**
* Provides a custom action for toggling repeat actions.
*/
public final class RepeatModeActionProvider implements MediaSessionConnector.CustomActionProvider {
private static final String ACTION_REPEAT_MODE = "ACTION_EXO_REPEAT_MODE";
private final @RepeatModeUtil.RepeatToggleModes int repeatToggleModes;
private final CharSequence repeatAllDescription;
private final CharSequence repeatOneDescription;
private final CharSequence repeatOffDescription;
/**
* Creates a new {@link RepeatModeActionProvider}.
* <p>
* This is equivalent to calling the two argument constructor with
* {@code RepeatModeUtil#REPEAT_TOGGLE_MODE_ONE | RepeatModeUtil#REPEAT_TOGGLE_MODE_ALL}.
*
* @param context The context.
*/
public RepeatModeActionProvider(Context context) {
this(context, RepeatModeUtil.REPEAT_TOGGLE_MODE_ONE | RepeatModeUtil.REPEAT_TOGGLE_MODE_ALL);
}
/**
* Creates a new {@link RepeatModeActionProvider} for the given repeat toggle modes.
*
* @param context The context.
* @param repeatToggleModes The toggle modes to enable.
*/
public RepeatModeActionProvider(Context context,
@RepeatModeUtil.RepeatToggleModes int repeatToggleModes) {
this.repeatToggleModes = repeatToggleModes;
repeatAllDescription = context.getString(R.string.exo_media_action_repeat_all_description);
repeatOneDescription = context.getString(R.string.exo_media_action_repeat_one_description);
repeatOffDescription = context.getString(R.string.exo_media_action_repeat_off_description);
}
@Override
public void onCustomAction(SimpleExoPlayer player, String action, Bundle extras) {
int mode = player.getRepeatMode();
int proposedMode = RepeatModeUtil.getNextRepeatMode(mode, repeatToggleModes);
if (mode != proposedMode) {
player.setRepeatMode(proposedMode);
}
}
@Override
public PlaybackStateCompat.CustomAction getCustomAction(SimpleExoPlayer player) {
CharSequence actionLabel;
int iconResourceId;
switch (player.getRepeatMode()) {
case ExoPlayer.REPEAT_MODE_ONE:
actionLabel = repeatOneDescription;
iconResourceId = R.drawable.exo_media_action_repeat_one;
break;
case ExoPlayer.REPEAT_MODE_ALL:
actionLabel = repeatAllDescription;
iconResourceId = R.drawable.exo_media_action_repeat_all;
break;
case ExoPlayer.REPEAT_MODE_OFF:
default:
actionLabel = repeatOffDescription;
iconResourceId = R.drawable.exo_media_action_repeat_off;
break;
}
PlaybackStateCompat.CustomAction.Builder repeatBuilder = new PlaybackStateCompat.CustomAction
.Builder(ACTION_REPEAT_MODE, actionLabel, iconResourceId);
return repeatBuilder.build();
}
}
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.android.exoplayer2.ext.mediasession;
import android.support.annotation.Nullable;
import android.support.v4.media.MediaDescriptionCompat;
import android.support.v4.media.session.MediaSessionCompat;
import android.support.v4.media.session.PlaybackStateCompat;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.ExoPlayer;
import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.util.Util;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* An abstract implementation of the {@link MediaSessionConnector.QueueNavigator} that's based on an
* {@link ExoPlayer}'s current {@link Timeline} and maps the timeline of the player to the media
* session queue.
*/
public abstract class TimelineQueueNavigator implements MediaSessionConnector.QueueNavigator {
public static final long MAX_POSITION_FOR_SEEK_TO_PREVIOUS = 3000;
public static final int DEFAULT_MAX_QUEUE_SIZE = 10;
private final MediaSessionCompat mediaSession;
private final int maxQueueSize;
private long activeQueueItemId;
/**
* Creates a new timeline queue navigator for a given {@link MediaSessionCompat}.
* <p>
* This is equivalent to calling
* {@code #TimelineQueueNavigator(mediaSession, DEFAULT_MAX_QUEUE_SIZE)}.
*
* @param mediaSession The {@link MediaSessionCompat}.
*/
public TimelineQueueNavigator(MediaSessionCompat mediaSession) {
this(mediaSession, DEFAULT_MAX_QUEUE_SIZE);
}
/**
* Creates a new timeline queue navigator for a given {@link MediaSessionCompat} and a maximum
* queue size of {@code maxQueueSize}.
* <p>
* If the actual queue size is larger than {@code maxQueueSize} a floating window of
* {@code maxQueueSize} is applied and moved back and forth when the user is navigating within the
* queue.
*
* @param mediaSession The {@link MediaSessionCompat}.
* @param maxQueueSize The maximum queue size.
*/
public TimelineQueueNavigator(MediaSessionCompat mediaSession, int maxQueueSize) {
this.mediaSession = mediaSession;
this.maxQueueSize = maxQueueSize;
activeQueueItemId = MediaSessionCompat.QueueItem.UNKNOWN_ID;
}
/**
* Gets the {@link MediaDescriptionCompat} for a given timeline window index.
*
* @param windowIndex The timeline window index for which to provide a description.
* @return A {@link MediaDescriptionCompat}.
*/
public abstract MediaDescriptionCompat getMediaDescription(int windowIndex);
@Override
public long getSupportedPlaybackActions() {
return PlaybackStateCompat.ACTION_SKIP_TO_NEXT | PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS
| PlaybackStateCompat.ACTION_SKIP_TO_QUEUE_ITEM;
}
@Override
public void onTimelineChanged(ExoPlayer player) {
publishFloatingQueueWindow(player);
}
@Override
public void onCurrentWindowIndexChanged(ExoPlayer player) {
publishFloatingQueueWindow(player);
}
@Override
public final long getActiveQueueItemId(@Nullable ExoPlayer player) {
return activeQueueItemId;
}
@Override
public final void onSkipToPrevious(ExoPlayer player) {
Timeline timeline = player.getCurrentTimeline();
if (timeline.isEmpty()) {
return;
}
int previousWindowIndex = timeline.getPreviousWindowIndex(player.getCurrentWindowIndex(),
player.getRepeatMode());
if (player.getCurrentPosition() > MAX_POSITION_FOR_SEEK_TO_PREVIOUS
|| previousWindowIndex == C.INDEX_UNSET) {
player.seekTo(0);
} else {
player.seekTo(previousWindowIndex, C.TIME_UNSET);
}
}
@Override
public final void onSkipToQueueItem(ExoPlayer player, long id) {
Timeline timeline = player.getCurrentTimeline();
if (timeline.isEmpty()) {
return;
}
int windowIndex = (int) id;
if (0 <= windowIndex && windowIndex < timeline.getWindowCount()) {
player.seekTo(windowIndex, C.TIME_UNSET);
}
}
@Override
public final void onSkipToNext(ExoPlayer player) {
Timeline timeline = player.getCurrentTimeline();
if (timeline.isEmpty()) {
return;
}
int nextWindowIndex = timeline.getNextWindowIndex(player.getCurrentWindowIndex(),
player.getRepeatMode());
if (nextWindowIndex != C.INDEX_UNSET) {
player.seekTo(nextWindowIndex, C.TIME_UNSET);
}
}
@Override
public void onSetShuffleModeEnabled(ExoPlayer player, boolean enabled) {
// TODO: Implement this.
}
private void publishFloatingQueueWindow(ExoPlayer player) {
if (player.getCurrentTimeline().isEmpty()) {
mediaSession.setQueue(Collections.<MediaSessionCompat.QueueItem>emptyList());
activeQueueItemId = MediaSessionCompat.QueueItem.UNKNOWN_ID;
return;
}
int windowCount = player.getCurrentTimeline().getWindowCount();
int currentWindowIndex = player.getCurrentWindowIndex();
int queueSize = Math.min(maxQueueSize, windowCount);
int startIndex = Util.constrainValue(currentWindowIndex - ((queueSize - 1) / 2), 0,
windowCount - queueSize);
List<MediaSessionCompat.QueueItem> queue = new ArrayList<>();
for (int i = startIndex; i < startIndex + queueSize; i++) {
queue.add(new MediaSessionCompat.QueueItem(getMediaDescription(i), i));
}
mediaSession.setQueue(queue);
activeQueueItemId = currentWindowIndex;
}
}
<!-- Copyright (C) 2017 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="32dp"
android:height="32dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M7,7h10v3l4,-4 -4,-4v3L5,5v6h2L7,7zM17,17L7,17v-3l-4,4 4,4v-3h12v-6h-2v4z"/>
</vector>
<!-- Copyright (C) 2017 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="32dp"
android:height="32dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#4EFFFFFF"
android:pathData="M7,7h10v3l4,-4 -4,-4v3L5,5v6h2L7,7zM17,17L7,17v-3l-4,4 4,4v-3h12v-6h-2v4z"/>
</vector>
<!-- Copyright (C) 2017 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:height="32dp"
android:width="32dp"
android:viewportHeight="24.0"
android:viewportWidth="24.0">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M7,7h10v3l4,-4 -4,-4v3L5,5v6h2L7,7zM17,17L7,17v-3l-4,4 4,4v-3h12v-6h-2v4zM13,15L13,9h-1l-2,1v1h1.5v4L13,15z"/>
</vector>
<?xml version="1.0"?>
<!--
Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<string name="exo_media_action_repeat_all_description">"Herhaal alles"</string>
<string name="exo_media_action_repeat_off_description">"Herhaal niks"</string>
<string name="exo_media_action_repeat_one_description">"Herhaal een"</string>
</resources>
<?xml version="1.0"?>
<!--
Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<string name="exo_media_action_repeat_all_description">"ሁሉንም ድገም"</string>
<string name="exo_media_action_repeat_off_description">"ምንም አትድገም"</string>
<string name="exo_media_action_repeat_one_description">"አንዱን ድገም"</string>
</resources>
<?xml version="1.0"?>
<!--
Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<string name="exo_media_action_repeat_all_description">"تكرار الكل"</string>
<string name="exo_media_action_repeat_off_description">"عدم التكرار"</string>
<string name="exo_media_action_repeat_one_description">"تكرار مقطع واحد"</string>
</resources>
<?xml version="1.0"?>
<!--
Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<string name="exo_media_action_repeat_all_description">"Bütün təkrarlayın"</string>
<string name="exo_media_action_repeat_one_description">"Təkrar bir"</string>
<string name="exo_media_action_repeat_off_description">"Heç bir təkrar"</string>
</resources>
<?xml version="1.0"?>
<!--
Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<string name="exo_media_action_repeat_all_description">"Ponovi sve"</string>
<string name="exo_media_action_repeat_off_description">"Ne ponavljaj nijednu"</string>
<string name="exo_media_action_repeat_one_description">"Ponovi jednu"</string>
</resources>
<?xml version="1.0"?>
<!--
Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<string name="exo_media_action_repeat_all_description">"Паўтарыць усё"</string>
<string name="exo_media_action_repeat_off_description">"Паўтараць ні"</string>
<string name="exo_media_action_repeat_one_description">"Паўтарыць адзін"</string>
</resources>
<?xml version="1.0"?>
<!--
Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<string name="exo_media_action_repeat_all_description">"Повтаряне на всички"</string>
<string name="exo_media_action_repeat_off_description">"Без повтаряне"</string>
<string name="exo_media_action_repeat_one_description">"Повтаряне на един елемент"</string>
</resources>
<?xml version="1.0"?>
<!--
Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<string name="exo_media_action_repeat_all_description">"সবগুলির পুনরাবৃত্তি করুন"</string>
<string name="exo_media_action_repeat_off_description">"একটিরও পুনরাবৃত্তি করবেন না"</string>
<string name="exo_media_action_repeat_one_description">"একটির পুনরাবৃত্তি করুন"</string>
</resources>
<?xml version="1.0"?>
<!--
Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<string name="exo_media_action_repeat_all_description">"Ponovite sve"</string>
<string name="exo_media_action_repeat_off_description">"Ne ponavljaju"</string>
<string name="exo_media_action_repeat_one_description">"Ponovite jedan"</string>
</resources>
<?xml version="1.0"?>
<!--
Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<string name="exo_media_action_repeat_all_description">"Repeteix-ho tot"</string>
<string name="exo_media_action_repeat_off_description">"No en repeteixis cap"</string>
<string name="exo_media_action_repeat_one_description">"Repeteix-ne un"</string>
</resources>
<?xml version="1.0"?>
<!--
Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<string name="exo_media_action_repeat_all_description">"Opakovat vše"</string>
<string name="exo_media_action_repeat_off_description">"Neopakovat"</string>
<string name="exo_media_action_repeat_one_description">"Opakovat jednu položku"</string>
</resources>
<?xml version="1.0"?>
<!--
Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<string name="exo_media_action_repeat_all_description">"Gentag alle"</string>
<string name="exo_media_action_repeat_off_description">"Gentag ingen"</string>
<string name="exo_media_action_repeat_one_description">"Gentag en"</string>
</resources>
<?xml version="1.0"?>
<!--
Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<string name="exo_media_action_repeat_all_description">"Alle wiederholen"</string>
<string name="exo_media_action_repeat_off_description">"Keinen Titel wiederholen"</string>
<string name="exo_media_action_repeat_one_description">"Einen Titel wiederholen"</string>
</resources>
<?xml version="1.0"?>
<!--
Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<string name="exo_media_action_repeat_all_description">"Επανάληψη όλων"</string>
<string name="exo_media_action_repeat_off_description">"Καμία επανάληψη"</string>
<string name="exo_media_action_repeat_one_description">"Επανάληψη ενός στοιχείου"</string>
</resources>
<?xml version="1.0"?>
<!--
Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<string name="exo_media_action_repeat_all_description">"Repeat all"</string>
<string name="exo_media_action_repeat_off_description">"Repeat none"</string>
<string name="exo_media_action_repeat_one_description">"Repeat one"</string>
</resources>
<?xml version="1.0"?>
<!--
Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<string name="exo_media_action_repeat_all_description">"Repeat all"</string>
<string name="exo_media_action_repeat_off_description">"Repeat none"</string>
<string name="exo_media_action_repeat_one_description">"Repeat one"</string>
</resources>
<?xml version="1.0"?>
<!--
Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<string name="exo_media_action_repeat_all_description">"Repeat all"</string>
<string name="exo_media_action_repeat_off_description">"Repeat none"</string>
<string name="exo_media_action_repeat_one_description">"Repeat one"</string>
</resources>
<?xml version="1.0"?>
<!--
Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<string name="exo_media_action_repeat_all_description">"Repetir todo"</string>
<string name="exo_media_action_repeat_off_description">"No repetir"</string>
<string name="exo_media_action_repeat_one_description">"Repetir uno"</string>
</resources>
<?xml version="1.0"?>
<!--
Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<string name="exo_media_action_repeat_all_description">"Repetir todo"</string>
<string name="exo_media_action_repeat_off_description">"No repetir"</string>
<string name="exo_media_action_repeat_one_description">"Repetir uno"</string>
</resources>
<?xml version="1.0"?>
<!--
Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<string name="exo_media_action_repeat_all_description">"Korda kõike"</string>
<string name="exo_media_action_repeat_off_description">"Ära korda midagi"</string>
<string name="exo_media_action_repeat_one_description">"Korda ühte"</string>
</resources>
<?xml version="1.0"?>
<!--
Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<string name="exo_media_action_repeat_all_description">"Errepikatu guztiak"</string>
<string name="exo_media_action_repeat_off_description">"Ez errepikatu"</string>
<string name="exo_media_action_repeat_one_description">"Errepikatu bat"</string>
</resources>
<?xml version="1.0"?>
<!--
Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<string name="exo_media_action_repeat_all_description">"تکرار همه"</string>
<string name="exo_media_action_repeat_off_description">"تکرار هیچ‌کدام"</string>
<string name="exo_media_action_repeat_one_description">"یک‌بار تکرار"</string>
</resources>
<?xml version="1.0"?>
<!--
Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<string name="exo_media_action_repeat_all_description">"Toista kaikki"</string>
<string name="exo_media_action_repeat_off_description">"Toista ei mitään"</string>
<string name="exo_media_action_repeat_one_description">"Toista yksi"</string>
</resources>
<?xml version="1.0"?>
<!--
Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<string name="exo_media_action_repeat_all_description">"Tout lire en boucle"</string>
<string name="exo_media_action_repeat_off_description">"Aucune répétition"</string>
<string name="exo_media_action_repeat_one_description">"Répéter un élément"</string>
</resources>
<?xml version="1.0"?>
<!--
Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<string name="exo_media_action_repeat_all_description">"Tout lire en boucle"</string>
<string name="exo_media_action_repeat_off_description">"Ne rien lire en boucle"</string>
<string name="exo_media_action_repeat_one_description">"Lire en boucle un élément"</string>
</resources>
<?xml version="1.0"?>
<!--
Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<string name="exo_media_action_repeat_all_description">"Repetir todo"</string>
<string name="exo_media_action_repeat_off_description">"Non repetir"</string>
<string name="exo_media_action_repeat_one_description">"Repetir un"</string>
</resources>
<?xml version="1.0"?>
<!--
Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<string name="exo_media_action_repeat_all_description">"બધા પુનરાવર્તન કરો"</string>
<string name="exo_media_action_repeat_off_description">"કંઈ પુનરાવર્તન કરો"</string>
<string name="exo_media_action_repeat_one_description">"એક પુનરાવર્તન કરો"</string>
</resources>
<?xml version="1.0"?>
<!--
Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<string name="exo_media_action_repeat_all_description">"सभी को दोहराएं"</string>
<string name="exo_media_action_repeat_off_description">"कुछ भी न दोहराएं"</string>
<string name="exo_media_action_repeat_one_description">"एक दोहराएं"</string>
</resources>
<?xml version="1.0"?>
<!--
Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<string name="exo_media_action_repeat_all_description">"Ponovi sve"</string>
<string name="exo_media_action_repeat_off_description">"Bez ponavljanja"</string>
<string name="exo_media_action_repeat_one_description">"Ponovi jedno"</string>
</resources>
<?xml version="1.0"?>
<!--
Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<string name="exo_media_action_repeat_all_description">"Összes ismétlése"</string>
<string name="exo_media_action_repeat_off_description">"Nincs ismétlés"</string>
<string name="exo_media_action_repeat_one_description">"Egy ismétlése"</string>
</resources>
<?xml version="1.0"?>
<!--
Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<string name="exo_media_action_repeat_all_description">"կրկնել այն ամենը"</string>
<string name="exo_media_action_repeat_off_description">"Չկրկնել"</string>
<string name="exo_media_action_repeat_one_description">"Կրկնել մեկը"</string>
</resources>
<?xml version="1.0"?>
<!--
Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<string name="exo_media_action_repeat_all_description">"Ulangi Semua"</string>
<string name="exo_media_action_repeat_off_description">"Jangan Ulangi"</string>
<string name="exo_media_action_repeat_one_description">"Ulangi Satu"</string>
</resources>
<?xml version="1.0"?>
<!--
Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<string name="exo_media_action_repeat_all_description">"Endurtaka allt"</string>
<string name="exo_media_action_repeat_off_description">"Endurtaka ekkert"</string>
<string name="exo_media_action_repeat_one_description">"Endurtaka eitt"</string>
</resources>
<?xml version="1.0"?>
<!--
Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<string name="exo_media_action_repeat_all_description">"Ripeti tutti"</string>
<string name="exo_media_action_repeat_off_description">"Non ripetere nessuno"</string>
<string name="exo_media_action_repeat_one_description">"Ripeti uno"</string>
</resources>
<?xml version="1.0"?>
<!--
Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<string name="exo_media_action_repeat_all_description">"חזור על הכל"</string>
<string name="exo_media_action_repeat_off_description">"אל תחזור על כלום"</string>
<string name="exo_media_action_repeat_one_description">"חזור על פריט אחד"</string>
</resources>
<?xml version="1.0"?>
<!--
Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<string name="exo_media_action_repeat_all_description">"全曲を繰り返し"</string>
<string name="exo_media_action_repeat_off_description">"繰り返しなし"</string>
<string name="exo_media_action_repeat_one_description">"1曲を繰り返し"</string>
</resources>
<?xml version="1.0"?>
<!--
Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<string name="exo_media_action_repeat_all_description">"გამეორება ყველა"</string>
<string name="exo_media_action_repeat_off_description">"გაიმეორეთ არცერთი"</string>
<string name="exo_media_action_repeat_one_description">"გაიმეორეთ ერთი"</string>
</resources>
<?xml version="1.0"?>
<!--
Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<string name="exo_media_action_repeat_all_description">"Барлығын қайталау"</string>
<string name="exo_media_action_repeat_off_description">"Ешқайсысын қайталамау"</string>
<string name="exo_media_action_repeat_one_description">"Біреуін қайталау"</string>
</resources>
<?xml version="1.0"?>
<!--
Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<string name="exo_media_action_repeat_all_description">"ធ្វើ​ម្ដង​ទៀត​ទាំងអស់"</string>
<string name="exo_media_action_repeat_off_description">"មិន​ធ្វើ​ឡើង​វិញ"</string>
<string name="exo_media_action_repeat_one_description">"ធ្វើ​​ឡើងវិញ​ម្ដង"</string>
</resources>
<?xml version="1.0"?>
<!--
Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<string name="exo_media_action_repeat_all_description">"ಎಲ್ಲವನ್ನು ಪುನರಾವರ್ತಿಸಿ"</string>
<string name="exo_media_action_repeat_off_description">"ಯಾವುದನ್ನೂ ಪುನರಾವರ್ತಿಸಬೇಡಿ"</string>
<string name="exo_media_action_repeat_one_description">"ಒಂದನ್ನು ಪುನರಾವರ್ತಿಸಿ"</string>
</resources>
<?xml version="1.0"?>
<!--
Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<string name="exo_media_action_repeat_all_description">"전체 반복"</string>
<string name="exo_media_action_repeat_off_description">"반복 안함"</string>
<string name="exo_media_action_repeat_one_description">"한 항목 반복"</string>
</resources>
<?xml version="1.0"?>
<!--
Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<string name="exo_media_action_repeat_all_description">"Баарын кайталоо"</string>
<string name="exo_media_action_repeat_off_description">"Эч бирин кайталабоо"</string>
<string name="exo_media_action_repeat_one_description">"Бирөөнү кайталоо"</string>
</resources>
<?xml version="1.0"?>
<!--
Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<string name="exo_media_action_repeat_all_description">"ຫຼິ້ນ​ຊ້ຳ​ທັງ​ໝົດ"</string>
<string name="exo_media_action_repeat_off_description">"​ບໍ່ຫຼິ້ນ​ຊ້ຳ"</string>
<string name="exo_media_action_repeat_one_description">"ຫຼິ້ນ​ຊ້ຳ"</string>
</resources>
<?xml version="1.0"?>
<!--
Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<string name="exo_media_action_repeat_all_description">"Kartoti viską"</string>
<string name="exo_media_action_repeat_off_description">"Nekartoti nieko"</string>
<string name="exo_media_action_repeat_one_description">"Kartoti vieną"</string>
</resources>
<?xml version="1.0"?>
<!--
Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<string name="exo_media_action_repeat_all_description">"Atkārtot visu"</string>
<string name="exo_media_action_repeat_off_description">"Neatkārtot nevienu"</string>
<string name="exo_media_action_repeat_one_description">"Atkārtot vienu"</string>
</resources>
<?xml version="1.0"?>
<!--
Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<string name="exo_media_action_repeat_all_description">"Повтори ги сите"</string>
<string name="exo_media_action_repeat_off_description">"Не повторувај ниту една"</string>
<string name="exo_media_action_repeat_one_description">"Повтори една"</string>
</resources>
<?xml version="1.0"?>
<!--
Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<string name="exo_media_action_repeat_all_description">"എല്ലാം ആവർത്തിക്കുക"</string>
<string name="exo_media_action_repeat_off_description">"ഒന്നും ആവർത്തിക്കരുത്"</string>
<string name="exo_media_action_repeat_one_description">"ഒന്ന് ആവർത്തിക്കുക"</string>
</resources>
<?xml version="1.0"?>
<!--
Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<string name="exo_media_action_repeat_all_description">"Бүгдийг давтах"</string>
<string name="exo_media_action_repeat_off_description">"Алийг нь ч давтахгүй"</string>
<string name="exo_media_action_repeat_one_description">"Нэгийг давтах"</string>
</resources>
<?xml version="1.0"?>
<!--
Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<string name="exo_media_action_repeat_all_description">"सर्व पुनरावृत्ती करा"</string>
<string name="exo_media_action_repeat_off_description">"काहीही पुनरावृत्ती करू नका"</string>
<string name="exo_media_action_repeat_one_description">"एक पुनरावृत्ती करा"</string>
</resources>
<?xml version="1.0"?>
<!--
Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<string name="exo_media_action_repeat_all_description">"Ulang semua"</string>
<string name="exo_media_action_repeat_off_description">"Tiada ulangan"</string>
<string name="exo_media_action_repeat_one_description">"Ulangan"</string>
</resources>
<?xml version="1.0"?>
<!--
Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<string name="exo_media_action_repeat_all_description">"အားလုံး ထပ်တလဲလဲဖွင့်ရန်"</string>
<string name="exo_media_action_repeat_off_description">"ထပ်တလဲလဲမဖွင့်ရန်"</string>
<string name="exo_media_action_repeat_one_description">"တစ်ခုအား ထပ်တလဲလဲဖွင့်ရန်"</string>
</resources>
<?xml version="1.0"?>
<!--
Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<string name="exo_media_action_repeat_all_description">"Gjenta alle"</string>
<string name="exo_media_action_repeat_off_description">"Ikke gjenta noen"</string>
<string name="exo_media_action_repeat_one_description">"Gjenta én"</string>
</resources>
<?xml version="1.0"?>
<!--
Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<string name="exo_media_action_repeat_all_description">"सबै दोहोर्याउनुहोस्"</string>
<string name="exo_media_action_repeat_off_description">"कुनै पनि नदोहोर्याउनुहोस्"</string>
<string name="exo_media_action_repeat_one_description">"एउटा दोहोर्याउनुहोस्"</string>
</resources>
<?xml version="1.0"?>
<!--
Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<string name="exo_media_action_repeat_all_description">"Alles herhalen"</string>
<string name="exo_media_action_repeat_off_description">"Niet herhalen"</string>
<string name="exo_media_action_repeat_one_description">"Eén herhalen"</string>
</resources>
<?xml version="1.0"?>
<!--
Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<string name="exo_media_action_repeat_all_description">"ਸਭ ਨੂੰ ਦੁਹਰਾਓ"</string>
<string name="exo_media_action_repeat_off_description">"ਕੋਈ ਵੀ ਨਹੀਂ ਦੁਹਰਾਓ"</string>
<string name="exo_media_action_repeat_one_description">"ਇੱਕ ਦੁਹਰਾਓ"</string>
</resources>
<?xml version="1.0"?>
<!--
Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<string name="exo_media_action_repeat_all_description">"Powtórz wszystkie"</string>
<string name="exo_media_action_repeat_off_description">"Nie powtarzaj"</string>
<string name="exo_media_action_repeat_one_description">"Powtórz jeden"</string>
</resources>
<?xml version="1.0"?>
<!--
Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<string name="exo_media_action_repeat_all_description">"Repetir tudo"</string>
<string name="exo_media_action_repeat_off_description">"Não repetir"</string>
<string name="exo_media_action_repeat_one_description">"Repetir um"</string>
</resources>
<?xml version="1.0"?>
<!--
Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<string name="exo_media_action_repeat_all_description">"Repetir tudo"</string>
<string name="exo_media_action_repeat_off_description">"Não repetir"</string>
<string name="exo_media_action_repeat_one_description">"Repetir um"</string>
</resources>
<?xml version="1.0"?>
<!--
Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<string name="exo_media_action_repeat_all_description">"Repetir tudo"</string>
<string name="exo_media_action_repeat_off_description">"Não repetir"</string>
<string name="exo_media_action_repeat_one_description">"Repetir uma"</string>
</resources>
<?xml version="1.0"?>
<!--
Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<string name="exo_media_action_repeat_all_description">"Repetați toate"</string>
<string name="exo_media_action_repeat_off_description">"Repetați niciuna"</string>
<string name="exo_media_action_repeat_one_description">"Repetați unul"</string>
</resources>
<?xml version="1.0"?>
<!--
Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<string name="exo_media_action_repeat_all_description">"Повторять все"</string>
<string name="exo_media_action_repeat_off_description">"Не повторять"</string>
<string name="exo_media_action_repeat_one_description">"Повторять один элемент"</string>
</resources>
<?xml version="1.0"?>
<!--
Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<string name="exo_media_action_repeat_all_description">"සියලු නැවත"</string>
<string name="exo_media_action_repeat_off_description">"කිසිවක් නැවත"</string>
<string name="exo_media_action_repeat_one_description">"නැවත නැවත එක්"</string>
</resources>
<?xml version="1.0"?>
<!--
Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<string name="exo_media_action_repeat_all_description">"Opakovať všetko"</string>
<string name="exo_media_action_repeat_off_description">"Neopakovať"</string>
<string name="exo_media_action_repeat_one_description">"Opakovať jednu položku"</string>
</resources>
<?xml version="1.0"?>
<!--
Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<string name="exo_media_action_repeat_all_description">"Ponovi vse"</string>
<string name="exo_media_action_repeat_off_description">"Ne ponovi"</string>
<string name="exo_media_action_repeat_one_description">"Ponovi eno"</string>
</resources>
<?xml version="1.0"?>
<!--
Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<string name="exo_media_action_repeat_all_description">"Përsërit të gjithë"</string>
<string name="exo_media_action_repeat_off_description">"Përsëritni asnjë"</string>
<string name="exo_media_action_repeat_one_description">"Përsëritni një"</string>
</resources>
<?xml version="1.0"?>
<!--
Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
</resources>
<?xml version="1.0"?>
<!--
Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<string name="exo_media_action_repeat_all_description">"Upprepa alla"</string>
<string name="exo_media_action_repeat_off_description">"Upprepa inga"</string>
<string name="exo_media_action_repeat_one_description">"Upprepa en"</string>
</resources>
<?xml version="1.0"?>
<!--
Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<string name="exo_media_action_repeat_all_description">"Rudia zote"</string>
<string name="exo_media_action_repeat_off_description">"Usirudie Yoyote"</string>
<string name="exo_media_action_repeat_one_description">"Rudia Moja"</string>
</resources>
<?xml version="1.0"?>
<!--
Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<string name="exo_media_action_repeat_all_description">"அனைத்தையும் மீண்டும் இயக்கு"</string>
<string name="exo_media_action_repeat_off_description">"எதையும் மீண்டும் இயக்காதே"</string>
<string name="exo_media_action_repeat_one_description">"ஒன்றை மட்டும் மீண்டும் இயக்கு"</string>
</resources>
<?xml version="1.0"?>
<!--
Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<string name="exo_media_action_repeat_all_description">"అన్నీ పునరావృతం చేయి"</string>
<string name="exo_media_action_repeat_off_description">"ఏదీ పునరావృతం చేయవద్దు"</string>
<string name="exo_media_action_repeat_one_description">"ఒకదాన్ని పునరావృతం చేయి"</string>
</resources>
<?xml version="1.0"?>
<!--
Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<string name="exo_media_action_repeat_all_description">"เล่นซ้ำทั้งหมด"</string>
<string name="exo_media_action_repeat_off_description">"ไม่เล่นซ้ำ"</string>
<string name="exo_media_action_repeat_one_description">"เล่นซ้ำรายการเดียว"</string>
</resources>
<?xml version="1.0"?>
<!--
Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<string name="exo_media_action_repeat_all_description">"Ulitin Lahat"</string>
<string name="exo_media_action_repeat_off_description">"Walang Uulitin"</string>
<string name="exo_media_action_repeat_one_description">"Ulitin ang Isa"</string>
</resources>
<?xml version="1.0"?>
<!--
Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<string name="exo_media_action_repeat_all_description">"Tümünü Tekrarla"</string>
<string name="exo_media_action_repeat_off_description">"Hiçbirini Tekrarlama"</string>
<string name="exo_media_action_repeat_one_description">"Birini Tekrarla"</string>
</resources>
<?xml version="1.0"?>
<!--
Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<string name="exo_media_action_repeat_all_description">"Повторити все"</string>
<string name="exo_media_action_repeat_off_description">"Не повторювати"</string>
<string name="exo_media_action_repeat_one_description">"Повторити один елемент"</string>
</resources>
<?xml version="1.0"?>
<!--
Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<string name="exo_media_action_repeat_all_description">"سبھی کو دہرائیں"</string>
<string name="exo_media_action_repeat_off_description">"کسی کو نہ دہرائیں"</string>
<string name="exo_media_action_repeat_one_description">"ایک کو دہرائیں"</string>
</resources>
<?xml version="1.0"?>
<!--
Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<string name="exo_media_action_repeat_all_description">"Barchasini takrorlash"</string>
<string name="exo_media_action_repeat_off_description">"Takrorlamaslik"</string>
<string name="exo_media_action_repeat_one_description">"Bir marta takrorlash"</string>
</resources>
<?xml version="1.0"?>
<!--
Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<string name="exo_media_action_repeat_all_description">"Lặp lại tất cả"</string>
<string name="exo_media_action_repeat_off_description">"Không lặp lại"</string>
<string name="exo_media_action_repeat_one_description">"Lặp lại một mục"</string>
</resources>
<?xml version="1.0"?>
<!--
Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<string name="exo_media_action_repeat_all_description">"重复播放全部"</string>
<string name="exo_media_action_repeat_off_description">"不重复播放"</string>
<string name="exo_media_action_repeat_one_description">"重复播放单个视频"</string>
</resources>
<?xml version="1.0"?>
<!--
Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<string name="exo_media_action_repeat_all_description">"重複播放所有媒體項目"</string>
<string name="exo_media_action_repeat_off_description">"不重複播放任何媒體項目"</string>
<string name="exo_media_action_repeat_one_description">"重複播放一個媒體項目"</string>
</resources>
<?xml version="1.0"?>
<!--
Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<string name="exo_media_action_repeat_all_description">"重複播放所有媒體項目"</string>
<string name="exo_media_action_repeat_off_description">"不重複播放"</string>
<string name="exo_media_action_repeat_one_description">"重複播放單一媒體項目"</string>
</resources>
<?xml version="1.0"?>
<!--
Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<string name="exo_media_action_repeat_all_description">"Phinda konke"</string>
<string name="exo_media_action_repeat_off_description">"Ungaphindi lutho"</string>
<string name="exo_media_action_repeat_one_description">"Phida okukodwa"</string>
</resources>
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<string name="exo_media_action_repeat_off_description">Repeat none</string>
<string name="exo_media_action_repeat_one_description">Repeat one</string>
<string name="exo_media_action_repeat_all_description">Repeat all</string>
</resources>
/*
* Copyright (c) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.android.exoplayer2.util;
import android.support.annotation.IntDef;
import com.google.android.exoplayer2.ExoPlayer;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
* Util class for repeat mode handling.
*/
public final class RepeatModeUtil {
/**
* Set of repeat toggle modes. Can be combined using bit-wise operations.
*/
@Retention(RetentionPolicy.SOURCE)
@IntDef(flag = true, value = {REPEAT_TOGGLE_MODE_NONE, REPEAT_TOGGLE_MODE_ONE,
REPEAT_TOGGLE_MODE_ALL})
public @interface RepeatToggleModes {}
/**
* All repeat mode buttons disabled.
*/
public static final int REPEAT_TOGGLE_MODE_NONE = 0;
/**
* "Repeat One" button enabled.
*/
public static final int REPEAT_TOGGLE_MODE_ONE = 1;
/**
* "Repeat All" button enabled.
*/
public static final int REPEAT_TOGGLE_MODE_ALL = 2;
private RepeatModeUtil() {
// Prevent instantiation.
}
/**
* Gets the next repeat mode out of {@code enabledModes} starting from {@code currentMode}.
*
* @param currentMode The current repeat mode.
* @param enabledModes Bitmask of enabled modes.
* @return The next repeat mode.
*/
public static @ExoPlayer.RepeatMode int getNextRepeatMode(
@ExoPlayer.RepeatMode int currentMode, int enabledModes) {
for (int offset = 1; offset <= 2; offset++) {
@ExoPlayer.RepeatMode int proposedMode = (currentMode + offset) % 3;
if (isRepeatModeEnabled(proposedMode, enabledModes)) {
return proposedMode;
}
}
return currentMode;
}
/**
* Verifies whether a given {@code repeatMode} is enabled in the bitmask {@code enabledModes}.
*
* @param repeatMode The mode to check.
* @param enabledModes The bitmask representing the enabled modes.
* @return {@code true} if enabled.
*/
public static boolean isRepeatModeEnabled(@ExoPlayer.RepeatMode int repeatMode,
int enabledModes) {
switch (repeatMode) {
case ExoPlayer.REPEAT_MODE_OFF:
return true;
case ExoPlayer.REPEAT_MODE_ONE:
return (enabledModes & REPEAT_TOGGLE_MODE_ONE) != 0;
case ExoPlayer.REPEAT_MODE_ALL:
return (enabledModes & REPEAT_TOGGLE_MODE_ALL) != 0;
default:
return false;
}
}
}
...@@ -22,7 +22,6 @@ import android.content.res.Resources; ...@@ -22,7 +22,6 @@ import android.content.res.Resources;
import android.content.res.TypedArray; import android.content.res.TypedArray;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.os.SystemClock; import android.os.SystemClock;
import android.support.annotation.IntDef;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.view.KeyEvent; import android.view.KeyEvent;
import android.view.LayoutInflater; import android.view.LayoutInflater;
...@@ -39,9 +38,8 @@ import com.google.android.exoplayer2.Timeline; ...@@ -39,9 +38,8 @@ import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.source.TrackGroupArray; import com.google.android.exoplayer2.source.TrackGroupArray;
import com.google.android.exoplayer2.trackselection.TrackSelectionArray; import com.google.android.exoplayer2.trackselection.TrackSelectionArray;
import com.google.android.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.Assertions;
import com.google.android.exoplayer2.util.RepeatModeUtil;
import com.google.android.exoplayer2.util.Util; import com.google.android.exoplayer2.util.Util;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Arrays; import java.util.Arrays;
import java.util.Formatter; import java.util.Formatter;
import java.util.Locale; import java.util.Locale;
...@@ -82,7 +80,7 @@ import java.util.Locale; ...@@ -82,7 +80,7 @@ import java.util.Locale;
* {@code all}, or {@code one|all}. * {@code all}, or {@code one|all}.
* <ul> * <ul>
* <li>Corresponding method: {@link #setRepeatToggleModes(int)}</li> * <li>Corresponding method: {@link #setRepeatToggleModes(int)}</li>
* <li>Default: {@link #DEFAULT_REPEAT_TOGGLE_MODES}</li> * <li>Default: {@link PlaybackControlView#DEFAULT_REPEAT_TOGGLE_MODES}</li>
* </ul> * </ul>
* </li> * </li>
* <li><b>{@code controller_layout_id}</b> - Specifies the id of the layout to be inflated. See * <li><b>{@code controller_layout_id}</b> - Specifies the id of the layout to be inflated. See
...@@ -249,30 +247,11 @@ public class PlaybackControlView extends FrameLayout { ...@@ -249,30 +247,11 @@ public class PlaybackControlView extends FrameLayout {
}; };
/**
* Set of repeat toggle modes. Can be combined using bit-wise operations.
*/
@Retention(RetentionPolicy.SOURCE)
@IntDef(flag = true, value = {REPEAT_TOGGLE_MODE_NONE, REPEAT_TOGGLE_MODE_ONE,
REPEAT_TOGGLE_MODE_ALL})
public @interface RepeatToggleModes {}
/**
* All repeat mode buttons disabled.
*/
public static final int REPEAT_TOGGLE_MODE_NONE = 0;
/**
* "Repeat One" button enabled.
*/
public static final int REPEAT_TOGGLE_MODE_ONE = 1;
/**
* "Repeat All" button enabled.
*/
public static final int REPEAT_TOGGLE_MODE_ALL = 2;
public static final int DEFAULT_FAST_FORWARD_MS = 15000; public static final int DEFAULT_FAST_FORWARD_MS = 15000;
public static final int DEFAULT_REWIND_MS = 5000; public static final int DEFAULT_REWIND_MS = 5000;
public static final int DEFAULT_SHOW_TIMEOUT_MS = 5000; public static final int DEFAULT_SHOW_TIMEOUT_MS = 5000;
public static final @RepeatToggleModes int DEFAULT_REPEAT_TOGGLE_MODES = REPEAT_TOGGLE_MODE_NONE; public static final @RepeatModeUtil.RepeatToggleModes int DEFAULT_REPEAT_TOGGLE_MODES
= RepeatModeUtil.REPEAT_TOGGLE_MODE_NONE;
/** /**
* The maximum number of windows that can be shown in a multi-window time bar. * The maximum number of windows that can be shown in a multi-window time bar.
...@@ -315,7 +294,7 @@ public class PlaybackControlView extends FrameLayout { ...@@ -315,7 +294,7 @@ public class PlaybackControlView extends FrameLayout {
private int rewindMs; private int rewindMs;
private int fastForwardMs; private int fastForwardMs;
private int showTimeoutMs; private int showTimeoutMs;
private @RepeatToggleModes int repeatToggleModes; private @RepeatModeUtil.RepeatToggleModes int repeatToggleModes;
private long hideAtMs; private long hideAtMs;
private long[] adGroupTimesMs; private long[] adGroupTimesMs;
private boolean[] playedAdGroups; private boolean[] playedAdGroups;
...@@ -424,8 +403,8 @@ public class PlaybackControlView extends FrameLayout { ...@@ -424,8 +403,8 @@ public class PlaybackControlView extends FrameLayout {
} }
@SuppressWarnings("ResourceType") @SuppressWarnings("ResourceType")
private static @RepeatToggleModes int getRepeatToggleModes(TypedArray a, private static @RepeatModeUtil.RepeatToggleModes int getRepeatToggleModes(TypedArray a,
@RepeatToggleModes int repeatToggleModes) { @RepeatModeUtil.RepeatToggleModes int repeatToggleModes) {
return a.getInt(R.styleable.PlaybackControlView_repeat_toggle_modes, repeatToggleModes); return a.getInt(R.styleable.PlaybackControlView_repeat_toggle_modes, repeatToggleModes);
} }
...@@ -535,28 +514,28 @@ public class PlaybackControlView extends FrameLayout { ...@@ -535,28 +514,28 @@ public class PlaybackControlView extends FrameLayout {
/** /**
* Returns which repeat toggle modes are enabled. * Returns which repeat toggle modes are enabled.
* *
* @return The currently enabled {@link RepeatToggleModes}. * @return The currently enabled {@link RepeatModeUtil.RepeatToggleModes}.
*/ */
public @RepeatToggleModes int getRepeatToggleModes() { public @RepeatModeUtil.RepeatToggleModes int getRepeatToggleModes() {
return repeatToggleModes; return repeatToggleModes;
} }
/** /**
* Sets which repeat toggle modes are enabled. * Sets which repeat toggle modes are enabled.
* *
* @param repeatToggleModes A set of {@link RepeatToggleModes}. * @param repeatToggleModes A set of {@link RepeatModeUtil.RepeatToggleModes}.
*/ */
public void setRepeatToggleModes(@RepeatToggleModes int repeatToggleModes) { public void setRepeatToggleModes(@RepeatModeUtil.RepeatToggleModes int repeatToggleModes) {
this.repeatToggleModes = repeatToggleModes; this.repeatToggleModes = repeatToggleModes;
if (player != null) { if (player != null) {
@ExoPlayer.RepeatMode int currentMode = player.getRepeatMode(); @ExoPlayer.RepeatMode int currentMode = player.getRepeatMode();
if (repeatToggleModes == REPEAT_TOGGLE_MODE_NONE if (repeatToggleModes == RepeatModeUtil.REPEAT_TOGGLE_MODE_NONE
&& currentMode != ExoPlayer.REPEAT_MODE_OFF) { && currentMode != ExoPlayer.REPEAT_MODE_OFF) {
controlDispatcher.dispatchSetRepeatMode(player, ExoPlayer.REPEAT_MODE_OFF); controlDispatcher.dispatchSetRepeatMode(player, ExoPlayer.REPEAT_MODE_OFF);
} else if (repeatToggleModes == REPEAT_TOGGLE_MODE_ONE } else if (repeatToggleModes == RepeatModeUtil.REPEAT_TOGGLE_MODE_ONE
&& currentMode == ExoPlayer.REPEAT_MODE_ALL) { && currentMode == ExoPlayer.REPEAT_MODE_ALL) {
controlDispatcher.dispatchSetRepeatMode(player, ExoPlayer.REPEAT_MODE_ONE); controlDispatcher.dispatchSetRepeatMode(player, ExoPlayer.REPEAT_MODE_ONE);
} else if (repeatToggleModes == REPEAT_TOGGLE_MODE_ALL } else if (repeatToggleModes == RepeatModeUtil.REPEAT_TOGGLE_MODE_ALL
&& currentMode == ExoPlayer.REPEAT_MODE_ONE) { && currentMode == ExoPlayer.REPEAT_MODE_ONE) {
controlDispatcher.dispatchSetRepeatMode(player, ExoPlayer.REPEAT_MODE_ALL); controlDispatcher.dispatchSetRepeatMode(player, ExoPlayer.REPEAT_MODE_ALL);
} }
...@@ -674,7 +653,7 @@ public class PlaybackControlView extends FrameLayout { ...@@ -674,7 +653,7 @@ public class PlaybackControlView extends FrameLayout {
if (!isVisible() || !isAttachedToWindow || repeatToggleButton == null) { if (!isVisible() || !isAttachedToWindow || repeatToggleButton == null) {
return; return;
} }
if (repeatToggleModes == REPEAT_TOGGLE_MODE_NONE) { if (repeatToggleModes == RepeatModeUtil.REPEAT_TOGGLE_MODE_NONE) {
repeatToggleButton.setVisibility(View.GONE); repeatToggleButton.setVisibility(View.GONE);
return; return;
} }
...@@ -859,30 +838,6 @@ public class PlaybackControlView extends FrameLayout { ...@@ -859,30 +838,6 @@ public class PlaybackControlView extends FrameLayout {
} }
} }
private @ExoPlayer.RepeatMode int getNextRepeatMode() {
@ExoPlayer.RepeatMode int currentMode = player.getRepeatMode();
for (int offset = 1; offset <= 2; offset++) {
@ExoPlayer.RepeatMode int proposedMode = (currentMode + offset) % 3;
if (isRepeatModeEnabled(proposedMode)) {
return proposedMode;
}
}
return currentMode;
}
private boolean isRepeatModeEnabled(@ExoPlayer.RepeatMode int repeatMode) {
switch (repeatMode) {
case ExoPlayer.REPEAT_MODE_OFF:
return true;
case ExoPlayer.REPEAT_MODE_ONE:
return (repeatToggleModes & REPEAT_TOGGLE_MODE_ONE) != 0;
case ExoPlayer.REPEAT_MODE_ALL:
return (repeatToggleModes & REPEAT_TOGGLE_MODE_ALL) != 0;
default:
return false;
}
}
private void rewind() { private void rewind() {
if (rewindMs <= 0) { if (rewindMs <= 0) {
return; return;
...@@ -1126,7 +1081,8 @@ public class PlaybackControlView extends FrameLayout { ...@@ -1126,7 +1081,8 @@ public class PlaybackControlView extends FrameLayout {
} else if (pauseButton == view) { } else if (pauseButton == view) {
controlDispatcher.dispatchSetPlayWhenReady(player, false); controlDispatcher.dispatchSetPlayWhenReady(player, false);
} else if (repeatToggleButton == view) { } else if (repeatToggleButton == view) {
controlDispatcher.dispatchSetRepeatMode(player, getNextRepeatMode()); controlDispatcher.dispatchSetRepeatMode(player, RepeatModeUtil.getNextRepeatMode(
player.getRepeatMode(), repeatToggleModes));
} }
} }
hideAfterTimeout(); hideAfterTimeout();
......
...@@ -49,6 +49,7 @@ import com.google.android.exoplayer2.trackselection.TrackSelectionArray; ...@@ -49,6 +49,7 @@ import com.google.android.exoplayer2.trackselection.TrackSelectionArray;
import com.google.android.exoplayer2.ui.AspectRatioFrameLayout.ResizeMode; import com.google.android.exoplayer2.ui.AspectRatioFrameLayout.ResizeMode;
import com.google.android.exoplayer2.ui.PlaybackControlView.ControlDispatcher; import com.google.android.exoplayer2.ui.PlaybackControlView.ControlDispatcher;
import com.google.android.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.Assertions;
import com.google.android.exoplayer2.util.RepeatModeUtil;
import com.google.android.exoplayer2.util.Util; import com.google.android.exoplayer2.util.Util;
import java.util.List; import java.util.List;
...@@ -637,9 +638,9 @@ public final class SimpleExoPlayerView extends FrameLayout { ...@@ -637,9 +638,9 @@ public final class SimpleExoPlayerView extends FrameLayout {
/** /**
* Sets which repeat toggle modes are enabled. * Sets which repeat toggle modes are enabled.
* *
* @param repeatToggleModes A set of {@link PlaybackControlView.RepeatToggleModes}. * @param repeatToggleModes A set of {@link RepeatModeUtil.RepeatToggleModes}.
*/ */
public void setRepeatToggleModes(@PlaybackControlView.RepeatToggleModes int repeatToggleModes) { public void setRepeatToggleModes(@RepeatModeUtil.RepeatToggleModes int repeatToggleModes) {
Assertions.checkState(controller != null); Assertions.checkState(controller != null);
controller.setRepeatToggleModes(repeatToggleModes); controller.setRepeatToggleModes(repeatToggleModes);
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment