Hi I have an Activity 1 which needs to send data to Appwidget (widget) which has a image view.
For sending data between activites i know that we can use intent.putExtra("mydata", dataString)
I send image from my adapter to my widget class but my image doesn't show up how can i fix that?
This is my adapter class I am sending data to adapter class
var intent=Intent(holder.itemView.context,AppWidgetBroadcast::class.java)
intent.putExtra("myimagedataWD",arraylist.get(position).imageimage)
This is my widget provider class
class AppWidgetBroadcast() : AppWidgetProvider() {
private lateinit var imageuri:String
private lateinit var parseUri:Uri
override fun onUpdate(
context: Context,
appWidgetManager: AppWidgetManager,
appWidgetIds: IntArray
) {
appWidgetIds.forEach { appWidgetId ->
// Create an Intent to launch ExampleActivity.
val pendingIntent: PendingIntent = PendingIntent.getActivity(
/* context = */ context,
/* requestCode = */ 0,
/* intent = */ Intent(context, WidgetDetailsActivity::class.java),
/* flags = */ PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
)
val views: RemoteViews = RemoteViews(context.packageName,R.layout.activity_widget_details).apply {
setOnClickPendingIntent(R.id.fullImageWidget, pendingIntent)
}
try {
var bitmap: Bitmap =
Glide.with(context)
.asBitmap()
.load(parseUri)
.submit(250, 250)
.get()
views.setImageViewBitmap(R.id.fullImageWidget,bitmap)
} catch (e: Exception) {
e.printStackTrace()
}
val id: Int = context.resources.getIdentifier(
"name",
null,
null
)
appWidgetManager.updateAppWidget(appWidgetId, views)
}
}
override fun onReceive(context: Context?, intent: Intent?) {
super.onReceive(context, intent)
if (intent != null) {
imageuri= intent.getStringExtra("myimagedataWD")!!
parseUri= Uri.parse(imageuri)
}
}
}
Related
I am using a BroadcastReceiver to send a broadcast to restart the FirebaseMessagingService when the service is destroyed. However, when starting service this way, the FirebaseMessagingService gets immediately destroyed. When the service is destroyed, I will send another broadcast to the receiver and the loop continues indefinitely.
My code for FirebaseMessagingService.
#AndroidEntryPoint
class MessagingService :
FirebaseMessagingService(),
FirebaseAuth.AuthStateListener {
companion object {
var isRunning = false
const val REQUEST_CODE = 0
const val NOTIFICATION_ID = 0
}
#Inject
lateinit var notificationRepository: NotificationRepository
#Inject
lateinit var authRepository: AuthRepository
override fun onCreate() {
super.onCreate()
Log.d("MessagingService", "I am created")
isRunning = true
FirebaseAuth.getInstance().addAuthStateListener(this)
}
override fun onDestroy() {
super.onDestroy()
Log.d("MessagingService", "I am destroyed")
isRunning = false
FirebaseAuth.getInstance().removeAuthStateListener(this)
val intent = Intent()
intent.action = "restartMessagingService"
intent.setClass(this, MessagingServiceRestarter::class.java)
this.sendBroadcast(intent)
}
override fun onMessageReceived(remoteMessage: RemoteMessage) {
val title = remoteMessage.notification?.title
val message = remoteMessage.notification?.body
if (message != null && title != null) {
sendPushNotification(title, message)
}
}
override fun onNewToken(token: String) {
saveTokenToSharedPreferences(token)
authRepository.getUser()?.let {
val uid = it.uid
sendTokenToFirestore(uid, token)
}
}
override fun onAuthStateChanged(auth: FirebaseAuth) {
auth.currentUser?.let {
val uid = it.uid
val savedRegistrationToken =
PreferenceManager.getDefaultSharedPreferences(this)
.getString(getString(R.string.fcm_token_shared_pref_key), "")
savedRegistrationToken?.let { token -> sendTokenToFirestore(uid, token) }
}
}
private fun sendPushNotification(title: String, messageBody: String) {
val intent = Intent(this, MainActivity::class.java)
val pendingIntent = PendingIntent.getActivity(this, REQUEST_CODE,
intent, PendingIntent.FLAG_UPDATE_CURRENT)
val channelId = getString(R.string.general_notification_channel_id)
val defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)
val notificationBuilder = NotificationCompat.Builder(this, channelId)
.setSmallIcon(R.drawable.mlearn_logo)
.setContentTitle(title)
.setContentText(messageBody)
.setAutoCancel(true)
.setSound(defaultSoundUri)
.setContentIntent(pendingIntent)
val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
val channel = NotificationChannel(
channelId,
getString(R.string.general_notification_channel_name),
NotificationManager.IMPORTANCE_DEFAULT
)
notificationManager.createNotificationChannel(channel)
notificationManager.notify(NOTIFICATION_ID, notificationBuilder.build())
}
private fun saveTokenToSharedPreferences(token: String) {
val sharedPref = PreferenceManager.getDefaultSharedPreferences(this)
with (sharedPref.edit()) {
putString(getString(R.string.fcm_token_shared_pref_key), token)
apply()
}
}
private fun sendTokenToFirestore(uid: String, token: String) {
GlobalScope.launch(Dispatchers.IO) {
notificationRepository.sendNotificationToken(uid, token)
}
}
}
My code for the receiver.
class MessagingServiceRestarter : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
Log.d("MessagingService", "Restarter" + MessagingService.isRunning.toString())
if (!MessagingService.isRunning) {
context.startService(Intent(context, MessagingService::class.java))
MessagingService.isRunning = true
}
}
}
I start my service every time the MainActivity is created.
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Log.d("MessagingService", "MainActivity" + MessagingService.isRunning.toString())
if (!MessagingService.isRunning) {
val intent = Intent(this, MessagingService::class.java)
startService(intent)
MessagingService.isRunning = true
}
}
override fun onDestroy() {
val intent = Intent()
Log.d("MessagingService", "MainActivity" + MessagingService.isRunning.toString())
intent.action = "restartMessagingService"
intent.setClass(this, MessagingServiceRestarter::class.java)
sendBroadcast(intent)
super.onDestroy()
}
And I have registered my service and receiver on manifest.
<service
android:name=".service.MessagingService"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
<receiver
android:name=".receiver.MessagingServiceRestarter"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="restartMessagingService"></action>
</intent-filter>
</receiver>
How can I keep my FirebaseMessagingService running? I am using this receiver to restart the service when the service is stopped because the app is cleared from the recent apps.
I would like to make api calls in background and show sometimes notifications due to api data. I had created service which make all calls:
class EndlessService : MyService() {
private var wakeLock: PowerManager.WakeLock? = null
private var isServiceStarted = false
override fun onBind(intent: Intent?): IBinder? {
log("Some component want to bind with the service")
// We don't provide binding, so return null
return null
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
log("onStartCommand executed with startId: $startId")
if (intent != null) {
val action = intent.action
log("using an intent with action $action")
when (action) {
Actions.START.name -> startService()
Actions.STOP.name -> stopService()
else -> log("This should never happen. No action in the received intent")
}
} else {
log(
"with a null intent. It has been probably restarted by the system."
)
}
// by returning this we make sure the service is restarted if the system kills the service
return START_STICKY
}
override fun onCreate() {
super.onCreate()
log("The service has been created".uppercase(Locale.ROOT))
startForeground(1, createNotification())
}
override fun onDestroy() {
super.onDestroy()
log("The service has been destroyed".uppercase(Locale.ROOT))
Toast.makeText(this, "Service destroyed", Toast.LENGTH_SHORT).show()
}
private fun startService() {
if (isServiceStarted) return
log("Starting the foreground service task")
Toast.makeText(this, "Service starting its task", Toast.LENGTH_SHORT).show()
isServiceStarted = true
setServiceState(this, ServiceState.STARTED)
// we need this lock so our service gets not affected by Doze Mode
wakeLock =
(getSystemService(Context.POWER_SERVICE) as PowerManager).run {
newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "EndlessService::lock").apply {
acquire(10*60*1000L /*10 minutes*/)
}
}
// we're starting a loop in a coroutine
GlobalScope.launch(Dispatchers.IO) {
while (isServiceStarted) {
launch(Dispatchers.IO) {
pingFakeServer()
}
delay(10 * 60)
}
log("End of the loop for the service")
}
}
private fun stopService() {
log("Stopping the foreground service")
Toast.makeText(this, "Service stopping", Toast.LENGTH_SHORT).show()
try {
wakeLock?.let {
if (it.isHeld) {
it.release()
}
}
stopForeground(true)
stopSelf()
} catch (e: Exception) {
log("Service stopped without being started: ${e.message}")
}
isServiceStarted = false
setServiceState(this, ServiceState.STOPPED)
}
private fun pingFakeServer() {
}
private fun createNotification(): Notification {
val notificationChannelId = "ENDLESS SERVICE CHANNEL"
// depending on the Android API that we're dealing with we will have
// to use a specific method to create the notification
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager;
val channel = NotificationChannel(
notificationChannelId,
"Endless Service notifications channel",
NotificationManager.IMPORTANCE_MIN
).let {
it.description = "Endless Service channel"
it.enableLights(true)
it.lightColor = Color.RED
it.enableVibration(true)
it.vibrationPattern = longArrayOf(100, 200, 300, 400, 500, 400, 300, 200, 400)
it
}
notificationManager.createNotificationChannel(channel)
}
val pendingIntent: PendingIntent = Intent(this, MainActivity::class.java).let { notificationIntent ->
PendingIntent.getActivity(this, 0, notificationIntent, 0)
}
val builder: Notification.Builder = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) Notification.Builder(
this,
notificationChannelId
) else Notification.Builder(this)
return builder
.setContentTitle("Endless Service")
.setContentText("This is your favorite endless service working")
.setContentIntent(pendingIntent)
.setSmallIcon(R.mipmap.ic_launcher)
.setTicker("Ticker text")
.setPriority(Notification.PRIORITY_MIN) // for under android 26 compatibility
.build()
}
}
then I added all info to the manifest and added classes for this service support:
enum class Actions {
START,
STOP
}
enum class ServiceState {
STARTED,
STOPPED,
}
private const val name = "SPYSERVICE_KEY"
private const val key = "SPYSERVICE_STATE"
fun setServiceState(context: Context, state: ServiceState) {
val sharedPrefs = getPreferences(context)
sharedPrefs.edit().let {
it.putString(key, state.name)
it.apply()
}
}
fun getServiceState(context: Context): ServiceState {
val sharedPrefs = getPreferences(context)
val value = sharedPrefs.getString(key, ServiceState.STOPPED.name)
return ServiceState.valueOf(value!!)
}
private fun getPreferences(context: Context): SharedPreferences {
return context.getSharedPreferences(name, 0)
}
and start it from an activity:
override fun onResume() {
super.onResume()
actionOnService(Actions.STOP)
}
override fun onPause() {
super.onPause()
actionOnService(Actions.START)
}
private fun actionOnService(action: Actions) {
if (getServiceState(this) == ServiceState.STOPPED && action == Actions.STOP) return
Intent(this, EndlessService::class.java).also {
it.action = action.name
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
log("Starting the service in >=26 Mode")
startForegroundService(it)
return
}
log("Starting the service in < 26 Mode")
startService(it)
}
}
but as I see such way creates empty notification which can't be dismissed. Maybe I can use another way?
it is my first time using maps sdk and i am having a lot of trouble to learn how to use it. I am creating an application which will send user's location to backend for each significant displacement, and a choose to use geofence to do it.
I built a foreground to detect when the user moves, even when his application is not open, but i can't get any event through the broadcast, even the initial trigger it cant hear, i am testing manually using fake gps app.
foreground service:
class LocationForegroundService : Service() {
private lateinit var geofencingClient: GeofencingClient
private lateinit var locationClient: FusedLocationProviderClient
val trackingWorking: Boolean get() = geoAlreadyInitialized
private val pendingBroadcastIntent: PendingIntent by lazy {
val intent = Intent(this, GeofenceReceiver::class.java)
PendingIntent.getBroadcast(
this,
0,
intent,
PendingIntent.FLAG_UPDATE_CURRENT
)
}
companion object {
private var geoAlreadyInitialized = false
private const val GEOFENCE_ID = "rider_location"
private const val TRACKING_CHANNEL = "tracking_channel"
private const val TRACKING_NOTIFICATION_ID = 1
private var count = 0
fun startService(context: Context) {
val startIntent = Intent(context, LocationForegroundService::class.java)
ContextCompat.startForegroundService(context, startIntent)
}
fun stopService(context: Context) {
val stopIntent = Intent(context, LocationForegroundService::class.java)
context.stopService(stopIntent)
}
}
override fun onCreate() {
super.onCreate()
locationClient = LocationServices.getFusedLocationProviderClient(this)
geofencingClient = LocationServices.getGeofencingClient(this)
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
...
getLastLocation()
return START_NOT_STICKY
}
#SuppressLint("MissingPermission")
private fun getLastLocation() {
if (geoAlreadyInitialized) geofencingClient.removeGeofences(pendingBroadcastIntent)
locationClient.lastLocation
.addOnSuccessListener { location ->
createGeofence(location)
++count
}
.addOnFailureListener {
print("fail")
// TODO WHEN NOTIFICATION IS BIND TO THE FRAGMENT SET TO PAUSE
}
}
private fun createGeofence(location: Location) {
val geofence = getGeofence(location)
val geofencingRequest = getGeofenceRequest(geofence)
createGeofenceEventListeners(geofencingRequest)
}
#SuppressLint("MissingPermission")
private fun createGeofenceEventListeners(geofencingRequest: GeofencingRequest) {
geofencingClient.addGeofences(geofencingRequest, pendingBroadcastIntent)
.addOnSuccessListener {
geoAlreadyInitialized = true
}
.addOnFailureListener {
// TODO
}
}
private fun getGeofenceRequest(geofence: Geofence) =
GeofencingRequest.Builder()
.setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_ENTER)
.addGeofence(geofence)
.build()
private fun getGeofence(it: Location) = Geofence.Builder()
.setCircularRegion(it.latitude, it.longitude, 5F)
.setRequestId(GEOFENCE_ID)
.setTransitionTypes(GEOFENCE_TRANSITION_EXIT)
.setExpirationDuration(NEVER_EXPIRE)
.setNotificationResponsiveness(0)
.build()
private fun createNotificationChannel() {...}
override fun onBind(intent: Intent?): IBinder? = null
class GeofenceReceiver : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
val geofencingEvent = GeofencingEvent.fromIntent(intent)
if (geofencingEvent.hasError()) {
return
}
when (geofencingEvent.geofenceTransition) {
GEOFENCE_TRANSITION_EXIT -> {
context?.showShortToast("EXIT geo blabla")
}
GEOFENCE_TRANSITION_ENTER -> {
context?.showShortToast("ENTER geo blabla")
}
GEOFENCE_TRANSITION_DWELL -> {
context?.showShortToast("dwell geo blabla")
}
}
}
}
}
Manifest
<receiver android:name=".util.LocationForegroundService$GeofenceReceiver"/>
to be more precise the broadcast is never called
val br = MyReceiver()
var filter = IntentFilter().apply { addAction(Intent.ACTION_SCREEN_ON)
}
var intent2 = Intent(requireActivity(), MyReceiver::class.java)
intent2.putExtra("Test", "value")
requireActivity().registerReceiver(br,filter)
requireActivity().sendBroadcast(intent2)
override fun onReceive(context: Context, intent: Intent) {
var st = intent.getStringExtra("Test")
Log.d("boradtest", st) // in normal operation
if (intent.action.equals(ACTION_SCREEN_ON)) {
var toast = Toast.makeText(context, st, Toast.LENGTH_LONG)
toast.show()
}
}
}
if (intent.action.equals(ACTION_SCREEN_ON))
The st value will be null at this point.
Please tell me what to do to receive the data normally
I use exoplayer in service for background streaming. And I found something strange. When I get the player at activity, the player is null. But the music is streaming and I can hear that song. Why the player in service is null even though it's streaming? I don't understand this. For example, If I click the musicOnOff Button, I get the null point error of player, but the music is streaming. please let me understand this...
error
kotlin.KotlinNullPointerException
Activity
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
private var mBound = false
var mIntent = Intent()
var audioService :AudioService ?= null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
audioService = AudioService()
mIntent = Intent(this,AudioService::class.java)
Util.startForegroundService(this,mIntent)
binding.musicOnOffButton.setOnClickListener {
initializePlayer()
}
}
private fun initializePlayer() {
if (mBound) {
val player: SimpleExoPlayer = audioService!!.getplayerInstance()!!
binding.musicPlayer.player = player
binding.musicPlayer.useController = true
}
}
override fun onResume() {
super.onResume()
bindService(mIntent, mConnection, Context.BIND_AUTO_CREATE)
}
override fun onPause() {
super.onPause()
unbindService(mConnection)
}
private val mConnection: ServiceConnection = object : ServiceConnection {
override fun onServiceConnected(componentName: ComponentName, iBinder: IBinder) {
mBound = true
//initializePlayer()
}
override fun onServiceDisconnected(componentName: ComponentName) {
}
}
}
Service
class AudioService : Service() {
private val mBinder: IBinder =Binder()
var player: SimpleExoPlayer? = null
private var cacheDataSourceFactory : CacheDataSourceFactory?=null
var mContext: Context? = null
lateinit var notification : Notification
override fun onDestroy() {
releasePlayer()
super.onDestroy()
}
override fun onCreate() {
super.onCreate()
Log.d("TAG","TAG : onCreate")
}
private fun releasePlayer() {
if (player != null) {
player!!.release()
player = null
}
}
override fun onBind(intent: Intent?): IBinder {
return mBinder
}
fun getplayerInstance(): SimpleExoPlayer? {
if (player == null) {
startPlayer(mContext!!)
}
return player
}
override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
Log.d("TAG","TAG : onStartCommand")
mContext = this
startPlayer(mContext!!)
val myNotificationListener = object :MyNotificationListener{
override fun onPlay() {
player!!.playWhenReady= !player!!.playWhenReady
}
override fun onRemove() {
stopSelf()
//stopForeground(true)
}
}
val receiver = NotificationBroadCast(myNotificationListener)
registerReceiver(receiver, IntentFilter("TRACKS_TRACKS"))
createNotification(
this,
MusicTrack("title 1","artist 1",R.drawable.reaction_happy),
1,
3
)
startForeground(NOTIFICATION_ID,notification)
return START_STICKY
}
private fun startPlayer(context: Context) {
val uri: Uri = Uri.parse("https://storage.googleapis.com/exoplayer-test-media-0/Jazz_In_Paris.mp3")
player = ExoPlayerFactory.newSimpleInstance(context, DefaultTrackSelector())
cacheDataSourceFactory = getCacheDataSourceFactory(context)
val mediaSource: MediaSource = ProgressiveMediaSource.Factory(cacheDataSourceFactory)
.createMediaSource(uri)
player!!.prepare(mediaSource)
player!!.setPlayWhenReady(true)
}
fun getCacheDataSourceFactory(context : Context) : CacheDataSourceFactory?{
if(cacheDataSourceFactory==null){
cacheDataSourceFactory = CacheDataSourceFactory(
context,
DefaultDataSourceFactory(context, "ua"),
MyExoPlayer.MAX_CACHE_VALUE, MyExoPlayer.MAX_CACHE_FILE_VALUE
)
}
return cacheDataSourceFactory
}
fun createNotification(context: Context, musicTrack: MusicTrack, pos:Int, size:Int){
val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
val resultIntent = Intent(context, MobileActivity::class.java)
resultIntent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP)
val resultPendingIntent: PendingIntent? = PendingIntent.getActivity(context,0,resultIntent, PendingIntent.FLAG_CANCEL_CURRENT)
var previousIntent :PendingIntent ?=null
var nextIntent :PendingIntent ?=null
var playIntent :PendingIntent ?=null
var image_prev = 0
var image_next = 0
if(pos==0){
previousIntent = null
image_prev =0
}else{
val intentPrevious = Intent(context,
NotificationReceiver::class.java).setAction(
MusicNotification.ACTION_PREVIOUS
)
previousIntent = PendingIntent.getBroadcast(context,0,intentPrevious,PendingIntent.FLAG_UPDATE_CURRENT)
image_prev = R.drawable.play_previous
}
if(pos==size){
nextIntent = null
image_next =0
}else{
val intentNext = Intent(context,
NotificationReceiver::class.java).setAction(
MusicNotification.ACTION_NEXT
)
nextIntent = PendingIntent.getBroadcast(context,0,intentNext,PendingIntent.FLAG_UPDATE_CURRENT)
image_next = R.drawable.play_next
}
val intentPlay = Intent(context,
NotificationReceiver::class.java).setAction(
MusicNotification.ACTION_PLAY
)
playIntent = PendingIntent.getBroadcast(context,0,intentPlay,PendingIntent.FLAG_UPDATE_CURRENT)
val intentCancel = Intent(context,
NotificationReceiver::class.java).setAction(
MusicNotification.ACTION_PLAY
)
val cancelIntent = PendingIntent.getBroadcast(context,0,intentCancel,PendingIntent.FLAG_UPDATE_CURRENT)
var binding = CustomNotificationBinding.inflate(LayoutInflater.from(context))
var contentView = RemoteViews(context.packageName, R.layout.custom_notification)
contentView.setTextViewText(binding.notiMusicName.id,musicTrack.title)
contentView.setOnClickPendingIntent(binding.prevButton.id,previousIntent)
contentView.setOnClickPendingIntent(binding.startButton.id,playIntent)
contentView.setOnClickPendingIntent(binding.nextButton.id,nextIntent)
notification = NotificationCompat.Builder(context, CHANNEL_ID)
.setSmallIcon(R.drawable.music_note)
.setOnlyAlertOnce(true)
.setShowWhen(false)
.setOngoing(true)
.setAutoCancel(true)
.setContent(contentView)
.setCustomContentView(contentView)
.setCustomBigContentView(contentView)
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setContentIntent(resultPendingIntent)
.setColorized(true)
.setColor(context.getColor(R.color.colorPrimary))
.build()
if(Build.VERSION.SDK_INT>= Build.VERSION_CODES.O){
val channelName ="Music Channel"
val channel = NotificationChannel(CHANNEL_ID,channelName, NotificationManager.IMPORTANCE_DEFAULT)
channel.enableLights(true)
channel.lightColor= 0x00FFFF
channel.setShowBadge(false)
notificationManager.createNotificationChannel(channel)
}
}
}
I solved this. because of my insufficient understanding about service and binder, I can't get the result I want.
I added Local Binder that point the current Service
added in AudioService
val mBinder: IBinder = LocalBinder()
inner class LocalBinder : Binder() {
val service: AudioService
get() = this#AudioService
}
added In MainActivity
private val mConnection: ServiceConnection = object : ServiceConnection {
override fun onServiceConnected(componentName: ComponentName, iBinder: IBinder) {
mBound = true
val binder = iBinder as AudioService.LocalBinder
audioService = binder.service
initializePlayer()
}
override fun onServiceDisconnected(componentName: ComponentName) {
}
}