Skip to content

Commit

Permalink
In app audio player (#3)
Browse files Browse the repository at this point in the history
Implement audio player in app
  • Loading branch information
TienDungUpwork authored May 7, 2022
1 parent 275864a commit 8830654
Show file tree
Hide file tree
Showing 23 changed files with 1,113 additions and 4 deletions.
2 changes: 1 addition & 1 deletion uikit-sample/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ apply plugin: 'com.android.application'
apply plugin: 'com.google.gms.google-services'

android {
compileSdkVersion 30
compileSdkVersion 31
buildToolsVersion "29.0.3"
defaultConfig {
applicationId "com.sendbird.uikit.sample"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,14 @@
import androidx.lifecycle.MutableLiveData;
import androidx.multidex.MultiDexApplication;

import com.sendbird.android.LogLevel;
import com.sendbird.android.SendBird;
import com.sendbird.android.SendBirdException;
import com.sendbird.android.handlers.InitResultHandler;
import com.sendbird.uikit.SendBirdUIKit;
import com.sendbird.uikit.adapter.SendBirdUIKitAdapter;
import com.sendbird.uikit.interfaces.UserInfo;
import com.sendbird.uikit.widgets.AudioPlayer;
import com.sendbird.uikit_messaging_android.consts.InitState;
import com.sendbird.uikit_messaging_android.fcm.MyFirebaseMessagingService;
import com.sendbird.uikit_messaging_android.utils.PreferenceUtils;
Expand Down Expand Up @@ -80,7 +83,10 @@ public void onInitSucceed() {
SendBirdUIKit.setDefaultThemeMode(useDarkTheme ? SendBirdUIKit.ThemeMode.Dark : SendBirdUIKit.ThemeMode.Light);
PushUtils.registerPushHandler(new MyFirebaseMessagingService());
SendBirdUIKit.setLogLevel(SendBirdUIKit.LogLevel.ALL);
SendBird.setLoggerLevel(LogLevel.VERBOSE);
SendBirdUIKit.setUseDefaultUserProfile(true);

AudioPlayer.getInstance().init(this);
}

public static LiveData<InitState> initStateChanges() {
Expand Down
4 changes: 3 additions & 1 deletion uikit/build.gradle
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
apply plugin: 'com.android.library'

android {
compileSdkVersion 30
compileSdkVersion 31
buildToolsVersion "29.0.3"

version = UIKIT_VERSION
Expand Down Expand Up @@ -79,6 +79,8 @@ dependencies {
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test:runner:1.3.0'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
implementation 'com.google.android.exoplayer:exoplayer:2.17.1'


implementation 'com.github.3llomi:RecordView:3.0.2'
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import com.sendbird.uikit.model.HighlightMessageInfo;
import com.sendbird.uikit.utils.ContextUtils;
import com.sendbird.uikit.utils.TextUtils;
import com.sendbird.uikit.widgets.AudioManager;

/**
* Activity displays a list of messages from a channel.
Expand Down Expand Up @@ -75,6 +76,14 @@ protected void onCreate(Bundle savedInstanceState) {
.replace(R.id.sb_fragment_container, fragment)
.commit();
}

AudioManager.getInstance().attachLifecycle(getLifecycle());
}

@Override
protected void onDestroy() {
AudioManager.getInstance().detachLifecycle(getLifecycle());
super.onDestroy();
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@ public enum MessageType {
VIEW_TYPE_ADMIN_MESSAGE(8),
VIEW_TYPE_TIME_LINE(9),
VIEW_TYPE_UNKNOWN_MESSAGE_ME(10),
VIEW_TYPE_UNKNOWN_MESSAGE_OTHER(11);
VIEW_TYPE_UNKNOWN_MESSAGE_OTHER(11),
VIEW_TYPE_FILE_MESSAGE_AUDIO_ME(12),
VIEW_TYPE_FILE_MESSAGE_AUDIO_OTHER(13);

int value;
MessageType(int value) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,12 @@ public static MessageViewHolder createViewHolder(@NonNull LayoutInflater inflate
case VIEW_TYPE_ADMIN_MESSAGE:
holder = new AdminMessageViewHolder(DataBindingUtil.inflate(inflater, R.layout.sb_view_admin_message, parent, false), false);
break;
case VIEW_TYPE_FILE_MESSAGE_AUDIO_ME:
holder = new MyAudioFileMessageViewHolder(DataBindingUtil.inflate(inflater, R.layout.sb_view_my_file_audio_message, parent, false), useMessageGroupUI);
break;
case VIEW_TYPE_FILE_MESSAGE_AUDIO_OTHER:
holder = new OtherAudioFileMessageViewHolder(DataBindingUtil.inflate(inflater, R.layout.sb_view_other_file_audio_message, parent, false), useMessageGroupUI);
break;
default:
// unknown message type
if (viewType == MessageType.VIEW_TYPE_UNKNOWN_MESSAGE_ME) {
Expand Down Expand Up @@ -150,7 +156,14 @@ public static MessageType getMessageType(@NonNull BaseMessage message) {
} else {
type = MessageType.VIEW_TYPE_FILE_MESSAGE_VIDEO_OTHER;
}
} else {
} else if (mimeType.startsWith(StringSet.audio)) {
if (MessageUtils.isMine(message)) {
type = MessageType.VIEW_TYPE_FILE_MESSAGE_AUDIO_ME;
} else {
type = MessageType.VIEW_TYPE_FILE_MESSAGE_AUDIO_OTHER;
}
}
else {
if (MessageUtils.isMine(message)) {
type = MessageType.VIEW_TYPE_FILE_MESSAGE_ME;
} else {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package com.sendbird.uikit.activities.viewholder;

import android.net.Uri;
import android.util.Log;
import android.view.View;

import androidx.annotation.NonNull;
import androidx.databinding.ViewDataBinding;

import com.sendbird.android.BaseChannel;
import com.sendbird.android.BaseMessage;
import com.sendbird.android.FileMessage;
import com.sendbird.android.Reaction;
import com.sendbird.uikit.BR;
import com.sendbird.uikit.consts.ClickableViewIdentifier;
import com.sendbird.uikit.consts.MessageGroupType;
import com.sendbird.uikit.interfaces.OnItemClickListener;
import com.sendbird.uikit.interfaces.OnItemLongClickListener;
import com.sendbird.uikit.widgets.EmojiReactionListView;
import com.sendbird.uikit.widgets.MyAudioFileMessageView;

import java.util.List;
import java.util.Map;

public final class MyAudioFileMessageViewHolder extends GroupChannelMessageViewHolder {
private final EmojiReactionListView emojiReactionListView;

MyAudioFileMessageViewHolder(@NonNull ViewDataBinding binding, boolean useMessageGroupUI) {
super(binding, useMessageGroupUI);
emojiReactionListView = ((MyAudioFileMessageView) binding.getRoot()).getBinding().rvEmojiReactionList;
final MyAudioFileMessageView root = (MyAudioFileMessageView) binding.getRoot();

clickableViewMap.put(ClickableViewIdentifier.QuoteReply.name(), root.getBinding().quoteReplyPanel);
}

@Override
public void bind(BaseChannel channel, @NonNull BaseMessage message, MessageGroupType messageGroupType) {
binding.setVariable(BR.channel, channel);
binding.setVariable(BR.message, message);
binding.setVariable(BR.messageGroupType, messageGroupType);

final MyAudioFileMessageView root = (MyAudioFileMessageView) binding.getRoot();
FileMessage fileMessage = (FileMessage) message;
String url = fileMessage.getUrl();
root.bind(Uri.parse(url));
}

@Override
public void setEmojiReaction(List<Reaction> reactionList,
OnItemClickListener<String> emojiReactionClickListener,
OnItemLongClickListener<String> emojiReactionLongClickListener,
View.OnClickListener moreButtonClickListener) {
emojiReactionListView.setReactionList(reactionList);
emojiReactionListView.setEmojiReactionClickListener(emojiReactionClickListener);
emojiReactionListView.setEmojiReactionLongClickListener(emojiReactionLongClickListener);
emojiReactionListView.setMoreButtonClickListener(moreButtonClickListener);
}

@Override
public Map<String, View> getClickableViewMap() {
return clickableViewMap;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package com.sendbird.uikit.activities.viewholder;

import android.net.Uri;
import android.view.View;

import androidx.annotation.NonNull;
import androidx.databinding.ViewDataBinding;

import com.sendbird.android.BaseChannel;
import com.sendbird.android.BaseMessage;
import com.sendbird.android.FileMessage;
import com.sendbird.android.Reaction;
import com.sendbird.uikit.BR;
import com.sendbird.uikit.consts.ClickableViewIdentifier;
import com.sendbird.uikit.consts.MessageGroupType;
import com.sendbird.uikit.interfaces.OnItemClickListener;
import com.sendbird.uikit.interfaces.OnItemLongClickListener;
import com.sendbird.uikit.widgets.EmojiReactionListView;
import com.sendbird.uikit.widgets.OtherAudioFileMessageView;

import java.util.List;
import java.util.Map;

public final class OtherAudioFileMessageViewHolder extends GroupChannelMessageViewHolder {
private final EmojiReactionListView emojiReactionListView;

OtherAudioFileMessageViewHolder(@NonNull ViewDataBinding binding, boolean useMessageGroupUI) {
super(binding, useMessageGroupUI);
emojiReactionListView = ((OtherAudioFileMessageView) binding.getRoot()).getBinding().rvEmojiReactionList;
final OtherAudioFileMessageView root = (OtherAudioFileMessageView) binding.getRoot();

clickableViewMap.put(ClickableViewIdentifier.Chat.name(), root.getBinding().ivThumbnailOveray);
clickableViewMap.put(ClickableViewIdentifier.QuoteReply.name(), root.getBinding().quoteReplyPanel);
}

@Override
public void bind(BaseChannel channel, @NonNull BaseMessage message, MessageGroupType messageGroupType) {
binding.setVariable(BR.channel, channel);
binding.setVariable(BR.message, message);
binding.setVariable(BR.messageGroupType, messageGroupType);

final OtherAudioFileMessageView root = (OtherAudioFileMessageView) binding.getRoot();
FileMessage fileMessage = (FileMessage) message;
String url = fileMessage.getUrl();
root.bind(Uri.parse(url));
}

@Override
public void setEmojiReaction(List<Reaction> reactionList,
OnItemClickListener<String> emojiReactionClickListener,
OnItemLongClickListener<String> emojiReactionLongClickListener,
View.OnClickListener moreButtonClickListener) {
emojiReactionListView.setReactionList(reactionList);
emojiReactionListView.setEmojiReactionClickListener(emojiReactionClickListener);
emojiReactionListView.setEmojiReactionLongClickListener(emojiReactionLongClickListener);
emojiReactionListView.setMoreButtonClickListener(moreButtonClickListener);
}

@Override
public Map<String, View> getClickableViewMap() {
return clickableViewMap;
}
}
114 changes: 114 additions & 0 deletions uikit/src/main/java/com/sendbird/uikit/widgets/AudioManager.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
package com.sendbird.uikit.widgets;

import android.net.Uri;

import androidx.lifecycle.Lifecycle;
import androidx.lifecycle.LifecycleObserver;
import androidx.lifecycle.OnLifecycleEvent;

import java.util.ArrayList;
import java.util.List;

public class AudioManager implements AudioPlayer.AudioPlayerListener, LifecycleObserver {

public interface AudioChangeListener {
void onAudioChanged(Uri uriPlaying, boolean isPlaying);
void onStateEnded(Uri uriPlaying);
void onIsPlayingChanged(Uri uriPlaying, boolean isPlaying);
}

private static AudioManager sInstance = null;
private Uri uriPlaying;

private final List<AudioChangeListener> listeners = new ArrayList<>();
private final AudioPlayer player = AudioPlayer.getInstance();

private AudioManager() {
player.setListener(this);
}

public static AudioManager getInstance() {
if (sInstance == null) {
sInstance = new AudioManager();
}
return sInstance;
}

public void attachLifecycle(Lifecycle lifecycle) {
lifecycle.addObserver(this);
}

public void detachLifecycle(Lifecycle lifecycle) {
stop();
lifecycle.removeObserver(this);
}

public void registerAudioChangeListener(AudioChangeListener listener) {
this.listeners.add(listener);
}

public void unregisterAudioChangeListener(AudioChangeListener listener) {
this.listeners.remove(listener);
}

private void notifyAudioChanged(boolean isPlaying) {
for (AudioChangeListener listener: listeners) {
listener.onAudioChanged(uriPlaying, isPlaying);
}
}

public void togglePlay(Uri uri) {
if (uriPlaying != uri) {
uriPlaying = uri;
player.stop();
player.start(uriPlaying);
notifyAudioChanged(true);
} else {
player.toggle();
notifyAudioChanged(player.isPlaying());
}
}

private void stop() {
uriPlaying = null;
player.stop();
notifyAudioChanged(false);
}

public boolean isUriPlaying(Uri uri) {
return uriPlaying != null && uri != null && uriPlaying.toString().equals(uri.toString());
}

public boolean isPlaying() {
return player.isPlaying();
}

public int getProgress() {
return (int) player.getCurrentProgress();
}

@Override
public void onStateEnded() {
for (AudioChangeListener listener: listeners) {
stop();
listener.onStateEnded(uriPlaying);
}
}

@Override
public void onIsPlayingChanged(boolean isPlaying) {
for (AudioChangeListener listener: listeners) {
listener.onIsPlayingChanged(uriPlaying, isPlaying);
}
}

@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
public void onPause() {
player.pause();
}

@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
public void onResume() {
player.resume();
}
}
Loading

0 comments on commit 8830654

Please sign in to comment.