I develop a Flutter plugin, the problem is FlutterPluginBinding.flutterEngine to get FlutterEngine is deprecated. Full code is below:
class AMPlugin : FlutterPlugin, MethodCallHandler, ActivityAware, PluginRegistry.ActivityResultListener {
private lateinit var channel: MethodChannel
private var activity: Activity? = null
override fun onAttachedToEngine(#NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
val engine = flutterPluginBinding.flutterEngine
channel = MethodChannel(engine.dartExecutor, "aM")
channel.setMethodCallHandler(this)
}
override fun onMethodCall(#NonNull call: MethodCall, #NonNull result: Result) {
when (call.method) {
else -> result.notImplemented()
}
}
override fun onDetachedFromEngine(#NonNull binding: FlutterPlugin.FlutterPluginBinding) {
channel.setMethodCallHandler(null)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?): Boolean {
return true
}
override fun onDetachedFromActivity() {
activity = null
}
override fun onReattachedToActivityForConfigChanges(binding: ActivityPluginBinding) {
activity = binding.activity
}
override fun onAttachedToActivity(binding: ActivityPluginBinding) {
activity = binding.activity
}
override fun onDetachedFromActivityForConfigChanges() {
activity = null
}
companion object {
#Suppress("UNUSED")
#JvmStatic
fun registerWith(registrar: Registrar) {
val channel = MethodChannel(registrar.messenger(), "aM")
channel.setMethodCallHandler(AMPlugin())
}
}
}
But I can't understand how to get FlutterEngine or initialize MethodChannel in another way. I tried as val engine = FlutterEngine(binding.applicationContext) but it leads to the crash, seems it requires Activity context.
How to replace this deprecated API?
replace:
channel = MethodChannel(engine.dartExecutor, "aM")
with
channel = MethodChannel(flutterPluginBinding.getBinaryMessenger(), "aM")
Related
Currently, I am trying to implement facebook-login in combination with cloud firestore inside my app. Everything works fine like it should (login, registration, Firebase.auth.currentUser != null).
The only problem I have is that when I log out of my app and then log in again with facebook I get the message "Up to now you have registered with xyz via Facebook. Do you want to continue."
I don't know why this message is coming. Even deleting the created facebook account from my cloud-firestore did not resolve the problem.
Here is a screenshot:
My Login Process
Fragment
class UserLogInRegistrationFragment : Fragment(R.layout.fragment_user_log_in_registration) {
private val viewModel: LoginViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Register Facebook Callback
viewModel.onEvent(LoginRegistrationEvent.RegisterFacebookCallback)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
initExternalLogins()
observeSignInOptions()
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
viewModel.onEvent(LoginRegistrationEvent.SignInWithFacebook(requestCode, resultCode, data))
}
override fun onDestroyView() {
super.onDestroyView()
// Unregister Facebook Callback
viewModel.onEvent(LoginRegistrationEvent.UnregisterFacebookCallback)
}
private fun initExternalLogins() {
facebookSignInBtn.setOnClickListener { viewModel.onEvent(LoginRegistrationEvent.OnStartFacebookSignIn) }
}
private fun observeSignInOptions() {
viewModel.signInOption.observe(viewLifecycleOwner) { event ->
when(event) {
is SignInOption.FacebookSignIn -> {
// Starting Login Process. This will be executed by the viewmodel
facebookManager().logInWithReadPermissions(this, listOf("email", "public_profile"))
}
}
}
}
}
Viewmodel
class LoginViewModel #Inject constructor(
private val loginValidator: LoginValidator
) : ViewModel() {
val signInOption = loginValidator.signInOption
val signInResult = loginValidator.signInResult
fun onEvent(event: LoginRegistrationEvent) {
when (event) {
LoginRegistrationEvent.RegisterFacebookCallback -> viewModelScope.launch { loginValidator.registerFacebookCallback() }
LoginRegistrationEvent.UnregisterFacebookCallback -> loginValidator.unregisterFacebookCallback()
LoginRegistrationEvent.OnStartFacebookSignIn -> loginValidator.startFacebookSignIn()
is LoginRegistrationEvent.SignInWithFacebook -> viewModelScope.launch {
loginValidator.handleFacebookSignInActivity(event.requestCode, event.resultCode, event.data)
}
}
}
}
LoginValidator (Use Case)
class LoginValidator #Inject constructor(
private val loginRepository: LoginRepository,
) {
private val _signInOption = MutableLiveData<SignInOption>()
val signInOption: LiveData<SignInOption> get() = _signInOption
private val _signInResult = MutableLiveData<LoginStateEvent>()
val signInResult: LiveData<LoginStateEvent> get() = _signInResult
fun startFacebookSignIn() {
_signInOption.value = SignInOption.FacebookSignIn
}
suspend fun registerFacebookCallback() {
loginRepository.signInWithFacebook().collect {
_signInResult.value = it
}
}
fun unregisterFacebookCallback() {
loginRepository.unregisterFacebookCallback()
}
fun handleFacebookSignInActivity(requestCode: Int, resultCode: Int, data: Intent?) {
loginRepository.handleFacebookSignInActivity(requestCode, resultCode, data)
}
fun signOut() = loginRepository.signOutUser()
}
LoginRepository
class LoginRepositoryImpl #Inject constructor(
#ApplicationContext private val context: Context,
private val callbackManager: CallbackManager,
private val dbAuth: FirebaseAuth,
private val dbFirestore: FirebaseFirestore
) : LoginRepository {
override fun isUserLogedIn(): Boolean = when (dbAuth.currentUser) {
null -> false
else -> true
}
override fun signOutUser() {
dbAuth.signOut()
facebookManager().logOut()
}
#ExperimentalCoroutinesApi
override suspend fun signInWithFacebook(): Flow<LoginStateEvent> = flow {
val result = facebookManager().registerMCallback(callbackManager)
emit(LoginStateEvent.Loading(context.getString(R.string.login_registration_progress_verify_facebook)))
val credential = FacebookAuthProvider.getCredential(result.accessToken.token)
emit(LoginStateEvent.Loading(context.getString(R.string.login_registration_progress_loggin_in)))
dbAuth.signInWithCredential(credential).await()
emit(LoginStateEvent.Loading(context.getString(R.string.login_regisration_progress_verifiy_rsb)))
createUserIfNotExist(
User(
eMail = dbAuth.currentUser!!.email ?: "",
lastName = splitToLastName(dbAuth.currentUser!!.displayName) ?: "",
firstName = splitToFirstName(dbAuth.currentUser!!.displayName) ?: "",
oAuth = OAuth.FACEBOOK
)
)
emit(LoginStateEvent.LoggedIn)
}.catch { e ->
emit(convertExceptionToState(e as Exception))
}
override fun handleFacebookSignInActivity(requestCode: Int, resultCode: Int, data: Intent?) {
callbackManager.onActivityResult(requestCode, resultCode, data)
}
override fun unregisterFacebookCallback() {
facebookManager().unregisterCallback(callbackManager)
}
Extension Function for Facebook Login
#ExperimentalCoroutinesApi
suspend fun LoginManager.registerMCallback(
manager: CallbackManager
) = suspendCancellableCoroutine<LoginResult> { cont ->
val callback = object : FacebookCallback<LoginResult> {
override fun onSuccess(result: LoginResult) = cont.resume(result, cont::resumeWithException)
override fun onCancel() { }
override fun onError(error: FacebookException?) {
error?.let { cont.resumeWithException(it) }
}
}
registerCallback(manager, callback)
}
fun facebookManager(): LoginManager = LoginManager.getInstance()
Callback Manager
#Provides
fun provideCallbackManager(): CallbackManager = CallbackManager.Factory.create()
Sign-In Flow
https://imgur.com/a/ZOjV5RZ
Dependencies I use
implementation "com.google.firebase:firebase-auth-ktx"
implementation 'com.facebook.android:facebook-login:8.1.0'
I have tried to stick to the cloud firestore documentation here and I've read this Stackoverflow post.
I need to create a Flutter plugin and link native Android code from ADA bot. I have no experience with android but by following the documentation, it should be simple:
val adaView = AdaEmbedView(getContext())
val adaSettings = AdaEmbedView.Settings.Builder("ada-example").build()
adaView.initialize(adaSettings)
val dialog = AdaEmbedDialog()
adaDialog.arguments = Bundle().apply {
putParcelable(AdaEmbedDialog.ARGUMENT_SETTINGS, settings)
}
dialog.show(supportFragmentManager, AdaEmbedDialog.TAG)
When I run this code I get the error:
Failed to handle method call
java.lang.IllegalStateException: FragmentManager has not been attached to a host.
I write the code in the flutter create plugin autogenerated file FlutterAdaPlugin.kt and it looks like this:
public class FlutterAdaPlugin: FlutterPlugin, ActivityAware, MethodCallHandler, PluginRegistry.ActivityResultListener, FragmentActivity() {
private lateinit var methodChannel : MethodChannel
private lateinit var eventChannel : EventChannel
private lateinit var eventSink : EventChannel.EventSink
private lateinit var adaFramerwork: AdaEmbedView
private lateinit var applicationCnt: Context
private var activity: Activity? = null
private lateinit var addaSettings: AdaEmbedView.Settings
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent) : Boolean {
super.onActivityResult(requestCode, resultCode, data)
return true
}
override fun onAttachedToEngine(#NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
onAttachedToEngine(flutterPluginBinding.applicationContext, flutterPluginBinding.binaryMessenger)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
this.applicationCnt = applicationContext
}
private fun onAttachedToEngine(applicationContext: Context, messenger: BinaryMessenger) {
this.applicationCnt = applicationContext
methodChannel = MethodChannel(messenger, "FlutterAdaPlugin")
eventChannel = EventChannel(messenger, "FlutterAdaPluginStream")
methodChannel.setMethodCallHandler(this)
eventChannel.setStreamHandler(object : EventChannel.StreamHandler {
override fun onListen(listener: Any?, eventSink: EventChannel.EventSink) {
this#FlutterAdaPlugin.eventSink = eventSink;
}
})
}
companion object {
#JvmStatic
fun registerWith(registrar: Registrar) {
val plugin = FlutterAdaPlugin()
plugin.activity = registrar.activity()
registrar.addActivityResultListener(plugin)
plugin.onAttachedToEngine(registrar.context(), registrar.messenger())
}
}
override fun onMethodCall(#NonNull call: MethodCall, #NonNull result: Result) {
when (call.method) {
"launchNavWebSupport" -> launchNavWebSupport()
}
else -> result.notImplemented()
}
}
private fun launchNavWebSupport() {
setupAdaFramework()
val dialog = AdaEmbedDialog()
dialog.arguments = Bundle().apply {
putParcelable(AdaEmbedDialog.ARGUMENT_SETTINGS, addaSettings)
}
if(supportFragmentManager != null) {
}
dialog.show(supportFragmentManager, AdaEmbedDialog.TAG)
}
private fun setupAdaFramework() {
val activity: Context = activity?.takeIf { activity != null } ?: return
adaFramerwork = AdaEmbedView(activity)
addaSettings = AdaEmbedView.Settings.Builder("test")
.build()
adaFramerwork.initialize(addaSettings)
}
override fun onDetachedFromEngine(#NonNull binding: FlutterPlugin.FlutterPluginBinding) {
eventChannel.setStreamHandler(null)
methodChannel.setMethodCallHandler(null)
}
override fun onAttachedToActivity(binding: ActivityPluginBinding) {
activity = binding.activity
binding.addActivityResultListener(this)
}
override fun onDetachedFromActivity() {
activity = null
}
override fun onReattachedToActivityForConfigChanges(binding: ActivityPluginBinding) {
activity = binding.activity
binding.addActivityResultListener(this)
}
override fun onDetachedFromActivityForConfigChanges() {
activity = null
}
}
I'm trying to get context in service. I know that Service extends Context and I can get it at onCreate method. So I tried it and got error. I don't understand other example uses the context at onCreate and works, but not to me. Also I registered my service. the error is occurred at this line in service.
player = ExoPlayerFactory.newSimpleInstance(mContext, DefaultTrackSelector())
Why the context is null even though I initialized the context in onCreate? I saw the similar problem at here Android getContext on a background Service
error
java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.Context android.content.Context.getApplicationContext()' on a null object reference
activity
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
val musicPlayer = binding.musicPlayer
musicPlayer.player = audioService.getplayerInstance()
musicPlayer.player.playWhenReady = true
mIntent = Intent(this,AudioService::class.java)
Util.startForegroundService(this,mIntent)
bindService(mIntent, mConnection, Context.BIND_AUTO_CREATE);
initializePlayer();
}
Service
class AudioService : Service() {
private val mBinder: IBinder =Binder()
private var player: SimpleExoPlayer? = null
private var playerNotificationManager: PlayerNotificationManager? = null
private var cacheDataSourceFactory : CacheDataSourceFactory?=null
var mContext: Context? = null
override fun onDestroy() {
releasePlayer()
super.onDestroy()
}
override fun onCreate() {
super.onCreate()
mContext = this
if (player == null) {
startPlayer()
}
}
private fun releasePlayer() {
if (player != null) {
playerNotificationManager!!.setPlayer(null)
player!!.release()
player = null
}
}
override fun onBind(intent: Intent?): IBinder {
return mBinder
}
fun getplayerInstance(): SimpleExoPlayer? {
if (player == null) {
startPlayer()
}
return player
}
override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
return START_STICKY
}
private fun startPlayer() {
val uri: Uri = Uri.parse("https://storage.googleapis.com/exoplayer-test-media-0/Jazz_In_Paris.mp3")
player = ExoPlayerFactory.newSimpleInstance(mContext, DefaultTrackSelector())
cacheDataSourceFactory = getCacheDataSourceFactory(mContext!!)
val mediaSource: MediaSource = ProgressiveMediaSource.Factory(cacheDataSourceFactory)
.createMediaSource(uri)
player!!.prepare(mediaSource)
player!!.setPlayWhenReady(true)
playerNotificationManager = PlayerNotificationManager.createWithNotificationChannel(
mContext,"channel_id", com.haii.exoplayerdemo.R.string.channelName,com.haii.exoplayerdemo.R.string.channelDescription,11,
object : PlayerNotificationManager.MediaDescriptionAdapter{
override fun createCurrentContentIntent(player: Player): PendingIntent? {
val intent = Intent(mContext,MainActivity::class.java)
return PendingIntent.getActivity(mContext,0,intent,PendingIntent.FLAG_UPDATE_CURRENT)
}
override fun getCurrentContentText(player: Player): String? {
return "description"
}
override fun getCurrentContentTitle(player: Player): String {
return "title"
}
override fun getCurrentLargeIcon(
player: Player,
callback: PlayerNotificationManager.BitmapCallback
): Bitmap? {
return null
}
} ,
object : PlayerNotificationManager.NotificationListener {
override fun onNotificationStarted(notificationId: Int, notification: Notification) {
Log.d("TAG","onNotificationStarted")
startForeground(notificationId,notification)
}
override fun onNotificationPosted(notificationId: Int, notification: Notification, ongoing: Boolean) {
Log.d("TAG","onNotificationPosted")
// startForeground(notificationId,notification)
}
override fun onNotificationCancelled(notificationId: Int, dismissedByUser: Boolean) {
Log.e("TAG","onNotificationCancelled 2")
stopSelf()
}
override fun onNotificationCancelled(notificationId: Int) {
Log.e("TAG","onNotificationCancelled 1")
// stopSelf()
}
}
)
playerNotificationManager!!.setPlayer(player)
}
fun getCacheDataSourceFactory(context : Context) : com.haii.exoplayerdemo.CacheDataSourceFactory?{
if(cacheDataSourceFactory==null){
cacheDataSourceFactory = com.haii.exoplayerdemo.CacheDataSourceFactory(
context,
DefaultDataSourceFactory(context, "ua"),
MyExoPlayer.MAX_CACHE_VALUE, MyExoPlayer.MAX_CACHE_FILE_VALUE
)
}
return cacheDataSourceFactory
}
}
I`m refering from here https://developer.android.com/guide/components/services.
The thing that you are doing wrong is calling getPlayerInstance() before onCreate is called. Your oncreate is called when you either bind or start the service. Good luck
I am trying to play audio using exoplayer.
I have multiple files in a local directory and I want to play them sequentially. I am trying to add multiple to URIs to MediaSource, but I couldn't find the solution.
Here, the first file is playing correctly but none of the rest. I am using the ExoPlayer version 2.9.2
Note: In my case the files in the "Articles" folder will be updated dynamically while player is running.
Please suggest a solution. My code:
class AudioPlayerService : Service() {
private var player: SimpleExoPlayer? = null
private var playerNotificationManager: PlayerNotificationManager? = null
private var mediaSession: MediaSessionCompat? = null
private var mediaSessionConnector: MediaSessionConnector? = null
private var dataSourceFactory: DataSource.Factory? = null
private var extractorsFactory: ExtractorsFactory? = null
private var dynamicConcatenatingMediaSource: ConcatenatingMediaSource? = null
override fun onCreate() {
super.onCreate()
val context: Context = this
player = ExoPlayerFactory.newSimpleInstance(this)
dataSourceFactory = DefaultDataSourceFactory(context, BuildConfig.APPLICATION_ID)
extractorsFactory = DefaultExtractorsFactory()
var file: File = File(Environment.getExternalStorageDirectory().absolutePath + "/Articles")
/*for (i in file.listFiles()){
Log.e("","" +file.listFiles())
}*/
var uri =
Uri.parse(Environment.getExternalStorageDirectory().absolutePath + "/Articles" + "/article_tts" + 0 + ".wav")
//if (dynamicConcatenatingMediaSource == null)
dynamicConcatenatingMediaSource = ConcatenatingMediaSource()
val mediaSource: MediaSource =
ExtractorMediaSource.Factory(dataSourceFactory).createMediaSource(uri)
dynamicConcatenatingMediaSource?.addMediaSource(mediaSource)
player?.prepare(dynamicConcatenatingMediaSource)
player?.setPlayWhenReady(true)
player?.addListener(object : Player.EventListener {
override fun onTracksChanged(
trackGroups: TrackGroupArray?,
trackSelections: TrackSelectionArray?
) {
}
override fun onPlayerError(error: ExoPlaybackException?) {
stopSelf()
}
override fun onLoadingChanged(isLoading: Boolean) {
}
override fun onPositionDiscontinuity(reason: Int) {
}
override fun onRepeatModeChanged(repeatMode: Int) {
}
override fun onShuffleModeEnabledChanged(shuffleModeEnabled: Boolean) {
}
override fun onTimelineChanged(timeline: Timeline?, manifest: Any?, reason: Int) {
}
override fun onPlayerStateChanged(playWhenReady: Boolean, playbackState: Int) {
if (playbackState == Player.STATE_ENDED) {
player?.stop()
stopSelf()
}
}
override fun onSeekProcessed() {
}
override fun onPlaybackParametersChanged(playbackParameters: PlaybackParameters?) {
}
})
playerNotificationManager = PlayerNotificationManager.createWithNotificationChannel(
context,
"playback_channel",
R.string.playback_channel_name,
7001,
object : MediaDescriptionAdapter {
override fun getCurrentContentTitle(player: Player): String {
return "Playlist"
}
override fun createCurrentContentIntent(player: Player): PendingIntent? {
return null
}
override fun getCurrentContentText(player: Player): String? {
return "Playlist Demo"
}
override fun getCurrentLargeIcon(
player: Player,
callback: BitmapCallback
): Bitmap? {
return getBitmap(context, R.drawable.ic_vikatan_logo_new)
}
}
)
playerNotificationManager?.setNotificationListener(object :
PlayerNotificationManager.NotificationListener {
override fun onNotificationStarted(
notificationId: Int,
notification: Notification
) {
startForeground(notificationId, notification)
}
override fun onNotificationCancelled(notificationId: Int) {
stopSelf()
}
})
playerNotificationManager?.setPriority(NotificationCompat.PRIORITY_HIGH);
playerNotificationManager?.setUseNavigationActions(false)
playerNotificationManager?.setFastForwardIncrementMs(0)
playerNotificationManager?.setRewindIncrementMs(0)
playerNotificationManager?.setUsePlayPauseActions(true);
playerNotificationManager?.setPlayer(player)
mediaSession = MediaSessionCompat(context, "audio")
mediaSession?.setActive(true)
playerNotificationManager?.setMediaSessionToken(mediaSession?.getSessionToken())
mediaSessionConnector = MediaSessionConnector(mediaSession)
mediaSessionConnector?.setQueueNavigator(object : TimelineQueueNavigator(mediaSession) {
override fun getMediaDescription(
player: Player,
windowIndex: Int
): MediaDescriptionCompat {
return getMediaDescription(context)
}
})
mediaSessionConnector?.setPlayer(player, null)
}
override fun onDestroy() {
mediaSession!!.release()
mediaSessionConnector!!.setPlayer(null, null)
playerNotificationManager!!.setPlayer(null)
player!!.release()
player = null
super.onDestroy()
}
override fun onBind(intent: Intent?): IBinder? {
return null
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
return START_STICKY
}
fun getBitmap(context: Context, #DrawableRes bitmapResource: Int): Bitmap {
return (context.resources.getDrawable(bitmapResource) as BitmapDrawable).bitmap
}
fun getMediaDescription(context: Context?): MediaDescriptionCompat {
val extras = Bundle()
val bitmap: Bitmap = getBitmap(context!!, R.drawable.ic_vikatan_logo_new)
extras.putParcelable(
MediaMetadataCompat.METADATA_KEY_ALBUM_ART,
bitmap
)
extras.putParcelable(
MediaMetadataCompat.METADATA_KEY_DISPLAY_ICON,
bitmap
)
return MediaDescriptionCompat.Builder()
.setMediaId("audio_id")
.setIconBitmap(bitmap)
.setTitle("Playlist")
.setDescription("Playlist Demo")
.setExtras(extras)
.build()
}
}
Use the concatenating media source.
private val concatenatingMediaSource = ConcatenatingMediaSource()
Then create separate mediasource for each audio file and add to concatenatingMediaSource by using
concatenatingMediaSource.addMediaSource(your_media_source_object)
I am trying to set the notification icon in my player which is using exoplayer. I have a playlist and am using concatenatingMediaSource. I have the url of the album art for every song but I dont know how I can set it as the notification icon. I read some answers which suggested using a AsyncTask and creating the notification onPostExecute() but I don't see how I can do in exoplayer playerNotificationManager.
Here is my Audio Service class:-
class AudioPlayerService: Service() {
private var player: SimpleExoPlayer? = null
private var playerNotificationManager: PlayerNotificationManager? = null
private var mediaSession: MediaSessionCompat? = null
private var mediaSessionConnector: MediaSessionConnector? = null
private var songList: ArrayList<MetaData>? = null
private var context: Context? = null
override fun onCreate() {
super.onCreate()
context = this
val descriptionAdapter = object : PlayerNotificationManager.MediaDescriptionAdapter {
override fun getCurrentContentTitle(player: Player?): String {
return songList!![player!!.currentWindowIndex].name
}
override fun getCurrentContentText(player: Player?): String? {
return songList!![player!!.currentWindowIndex].artist
}
override fun getCurrentLargeIcon(player: Player?, callback: PlayerNotificationManager.BitmapCallback?): Bitmap? {
return null
}
override fun createCurrentContentIntent(player: Player?): PendingIntent? {
val intent = Intent(context, MainActivity::class.java)
return PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT)
}
}
playerNotificationManager = PlayerNotificationManager.createWithNotificationChannel(
this, "1", R.string.notification_name, 1, descriptionAdapter
)
val notificationListener = object : PlayerNotificationManager.NotificationListener {
override fun onNotificationStarted(notificationId: Int, notification: Notification?) {
startForeground(notificationId, notification)
}
override fun onNotificationCancelled(notificationId: Int) {
stopSelf()
}
}
playerNotificationManager!!.setNotificationListener(
notificationListener
)
mediaSession = MediaSessionCompat(context, "Test")
mediaSession!!.isActive = true
playerNotificationManager!!.setMediaSessionToken(mediaSession!!.sessionToken)
mediaSessionConnector = MediaSessionConnector(mediaSession)
val timelineQueueNavigator = object: TimelineQueueNavigator(mediaSession) {
override fun getMediaDescription(player: Player?, windowIndex: Int): MediaDescriptionCompat {
return getMediaDescription(songList!![windowIndex])
}
}
mediaSessionConnector!!.setQueueNavigator(timelineQueueNavigator)
}
override fun onDestroy() {
super.onDestroy()
mediaSession!!.release()
mediaSessionConnector!!.setPlayer(null, null)
playerNotificationManager!!.setPlayer(null)
player!!.release()
player = null
}
override fun onBind(p0: Intent?): IBinder? {
return null
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
songList = intent!!.getParcelableArrayListExtra<MetaData>("list")
context = this
player = ExoPlayerFactory.newSimpleInstance(this, DefaultTrackSelector())
val dataSource = DefaultDataSourceFactory(
this, Util.getUserAgent(this, getString(R.string.app_name)))
val concatenatingMediaSource = ConcatenatingMediaSource()
for(item in songList!!){
val mediaSource = ExtractorMediaSource.Factory(dataSource)
.createMediaSource(Uri.parse(item.url))
concatenatingMediaSource.addMediaSource(mediaSource)
}
player!!.prepare(concatenatingMediaSource)
player!!.playWhenReady = true
playerNotificationManager!!.setPlayer(player)
mediaSessionConnector!!.setPlayer(player, null)
return START_STICKY
}
private fun getMediaDescription(item: MetaData): MediaDescriptionCompat {
return MediaDescriptionCompat.Builder()
.setMediaId(item.id.toString())
.setTitle(item.name)
.setDescription(item.artist)
.setMediaUri(Uri.parse(item.url))
.build()
}
}
Thanks in advance.
You can use Glide for it in overrided function getCurrentLargeIcon
override fun getCurrentLargeIcon(
player: Player?,
callback: PlayerNotificationManager.BitmapCallback?
): Bitmap? {
loadBitmap(currentStation?.cover, callback)
return null //or stub image
}
private fun loadBitmap(url: String, callback: PlayerNotificationManager.BitmapCallback?) {
Glide.with(this)
.asBitmap()
.load(url)
.into(object : CustomTarget<Bitmap>() {
override fun onResourceReady(
resource: Bitmap,
transition: Transition<in Bitmap>?
) {
callback?.onBitmap(resource)
}
})
}
You need to override it like this
#Nullable
#Override
public Bitmap getCurrentLargeIcon(Player player, PlayerNotificationManager.BitmapCallback callback) {
Glide.with(this)
.asBitmap()
.load(uri)
.into(new CustomTarget<Bitmap>() {
#Override
public void onResourceReady(#NonNull Bitmap resource, #Nullable Transition<? super Bitmap> transition) {
callback.onBitmap(resource);
}
#Override
public void onLoadCleared(#Nullable Drawable placeholder) {
}
});
return null;
}