I am trying to developing JobScheduler, and I want the App to do something every 1 minute when App has been killed by system.
AndroidManifest.xml
<service
android:name=".BaiduPush.BaiduJobService"
android:enabled="true"
android:permission="android.permission.BIND_JOB_SERVICE"/>
MainActivity
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = DataBindingUtil.setContentView(this, R.layout.activity_main2)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
startJobService()
}
}
private fun startJobService() {
Log.d(TAG,"startBaiduJobService")
val JOB = 10
val jobScheler = getSystemService((Context.JOB_SCHEDULER_SERVICE)) as JobScheduler
val jobinfo = JobInfo.Builder(JOB, ComponentName(packageName,BaiduJobService::class.java.name))
//.setPeriodic(AlarmManager.INTERVAL_FIFTEEN_MINUTES)
.setOverrideDeadline(60000)
.setPersisted(true)
.build()
jobScheler.schedule(jobinfo)
}
BaiduJobService
class BaiduJobService : JobService() {
val TAG = "BaiduJobService"
override fun onStartJob(params: JobParameters?): Boolean {
Log.d(TAG,"BaiduJobService onStartJob")
return true
}
override fun onStopJob(params: JobParameters?): Boolean {
return false
}
}
When I use the setPeriodic(AlarmManager.INTERVAL_FIFTEEN_MINUTES). The onStartJob has not been called.
When I use the setOverrideDeadline(60000). The onStartJob only show once times at the first.
But the BaiduJobService seems not called when time is up.
Did I missing something? Thanks in advance.
I am Using Alarm Manager For Keep my service alive it is better than a job scheduler. I implement this code in service oncreate() method.
public class CallService extends Service {
#Override
public void onCreate() {
super.onCreate();
Intent intent = new Intent(this, RestartServiceBroadcast.class);
mKeepAlivePendingIntent = PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
((AlarmManager) this.getSystemService(Context.ALARM_SERVICE)).setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + 60000, 60000, mKeepAlivePendingIntent);
}
}
Create BroadcastReceiver to call service again in onRecieve
public class RestartServiceBroadcast extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals("service.RestartService")) {
// Here Call a Service
}
}
}
Manifest Like this
<receiver
android:name=".service.receiver.RestartServiceBroadcast"
android:enabled="true"
android:exported="true"
android:process=":sipStack">
<intent-filter>
<action android:name="service.RestartService" />
</intent-filter>
</receiver>
<service
android:name=".service.CallService"
android:enabled="true"
android:exported="false"
android:stopWithTask="false">
</service>
Related
I am trying to implement the wifi change state feature in my Activity but I am getting multiple time calls in Receive.
public class MyReceiver extends BroadcastReceiver {
private IStatusChangeListener listener;
#Override
public void onReceive(final Context context, final Intent intent) {
String status = getConnectivityStatusString(context);
Log.d("network", status);
if (status.isEmpty() || status.equals("Wifi enabled") || status.equals("Wifi enabled")) {
listener.onConnected(true);
} else {
Toast.makeText(context, "NOt Connected", Toast.LENGTH_LONG).show();
listener.onConnected(false);
}
}
public void myBrodCastReceiver(IStatusChangeListener listener) {
this.listener = listener;
}
}
in my Activity :
lateinit var myReceiver: MyReceiver
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
AndroidInjection.inject(this)
setContentView(R.layout.activity_r3_main)
setSupportActionBar(toolbarmain)
val radius = resources.getDimension(R.dimen.roundcorner)
txtRove.text = getString(R.string.txt_live_video)
myReceiver = MyReceiver()
myReceiver.myBrodCastReceiver(this)
}
override fun onStart() {
super.onStart()
this.registerReceiver(myReceiver, IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION))
}
override fun onPause() {
super.onPause()
this.unregisterReceiver(myReceiver);
}
in my Android manifest file :
<receiver android:name = "com.rovedashcam.newmodeule.base.wifirecciver.MyReceiver" android:exported="true">
<intent-filter>
<action android:name = "android.net.conn.CONNECTIVITY_CHANGE"
tools:ignore="BatteryLife" />
<action android:name = "android.net.wifi.WIFI_STATE_CHANGED" />
</intent-filter>
</receiver>
when I try to get the run code then I get multiple time calls back in MyReceiver class onReceive method I have to register the broadcast Receiver from one place and unregister from onpause method but I don't know why it's calling two times please help me in this.
You have registered the BroadcastReceiver twice. Once in the manifest and again in code. You only need to do the one or the other. If you want to register your BroadcastReceiver dynamically (in code), then remove the <receiver> declaration from the manifest.
I have read multiple threads on this issue but none of them solved my problem, so I gave up and decided to write this.
I have a service (right now it's a background service but I am going to turn it into a foreground service) which monitors the battery level so it can notify the user when it reaches a certain percentage.
abstract class MonitoringService : Service() {
private var maxPercentage: Int = -1
private var thread: Thread? = null
private lateinit var batteryManager: BatteryManager
override fun onBind(intent: Intent?): IBinder? {
return null
}
override fun onCreate() {
batteryManager = getSystemService(BATTERY_SERVICE) as BatteryManager
Log.d(null, "created service")
}
override fun onDestroy() {
thread?.interrupt()
updateServiceState(false)
Log.d(null, "destroyed service")
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
println("started service")
if (intent == null) {
stopSelf(startId)
updateServiceState(false)
report(applicationContext, "service started with intent null")
return START_NOT_STICKY
}
when (intent.action) {
ACTION_START_SERVICE -> {
// if a thread is already active interrupt it
thread?.interrupt()
if (updateMaxPercentage(intent, startId) == 1) return START_NOT_STICKY
thread = Thread(Runnable {
while (true) {
if (batteryManager.isCharging && batteryManager.getIntProperty(
BatteryManager.BATTERY_PROPERTY_CAPACITY
) == maxPercentage
) {
Log.d(null, "time to do it")
}
Log.d(null, "time to not do it")
try {
// sleep for 1 minute
Thread.sleep(60000)
} catch (exception: InterruptedException) {
stopSelf(startId)
updateServiceState(false)
return#Runnable
}
}
})
thread?.start()
updateServiceState(true)
}
ACTION_STOP_SERVICE -> {
thread?.interrupt()
stopSelf(startId)
updateServiceState(false)
return START_NOT_STICKY
}
ACTION_UPDATE_SERVICE -> if (updateMaxPercentage(intent, startId) == 1) return START_NOT_STICKY
else -> {
stopSelf(startId)
updateServiceState(false)
report(applicationContext, "service started with action null")
return START_NOT_STICKY
}
}
return START_REDELIVER_INTENT
}
}
I start the service like so from my activity
private fun start() {
val serviceIntent = Intent(applicationContext, MonitoringService::class.java)
serviceIntent.action = ACTION_START_SERVICE
serviceIntent.putExtra("maxPercentage", maxPercentage)
println(startService(intent))
Log.d(null, "startService")
}
This is my AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.segv.batconv">
<application
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:theme="#style/Theme.Batconv"
tools:targetApi="31">
<service
android:name=".MonitoringService"
android:enabled="true"/>
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
I am testing this on an Android 11 device. The logs show no errors but the service doesn't start.
Thanks.
Remove the abstract keyword from your MonitoringService declaration:
class MonitoringService : Service()
By declaring it abstract, you are saying that nothing can create an instance of that class.
There is a task to make it so that when an application is deleted from the phone, my application sends a notification: "application name" has been deleted.
I do it like this:
Manifest
<receiver
android:name=".MyReceiver"
android:enabled="true"
android:exported="false">
<intent-filter>
<action android:name="servicereload" />
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
<service
android:name=".MyService"
android:enabled="true"
android:exported="true" >
</service>
MainActivity
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val notificationManagerCompat = NotificationManagerCompat.from(this)
notificationManagerCompat.cancelAll()
val serviceIntent = Intent(this, MyService::class.java)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
ContextCompat.startForegroundService(this, serviceIntent)
} else {
startService(Intent(this, MyService::class.java))
}
val intentFilter = IntentFilter()
intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED)
intentFilter.addDataScheme("package")
registerReceiver(MyReceiver(), intentFilter)
}
}
MyReceiver
class MyReceiver: BroadcastReceiver() {
val CHANNEL_ID = "ServiceChannel"
#SuppressLint("RemoteViewLayout")
override fun onReceive(context: Context?, intent: Intent?) {
var packageName = ""
try {
packageName = Objects.requireNonNull(intent!!.data)!!.encodedSchemeSpecificPart
Toast.makeText(context, "USER UNINSTALL : $packageName", Toast.LENGTH_SHORT).show()
Log.i("MyLog", "USER UNINSTALL : $packageName")
} catch (ex: Exception) {
Log.i("MyLog", "Exception: $ex")
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val notificationChannel = NotificationChannel(CHANNEL_ID, "Channel", NotificationManager.IMPORTANCE_DEFAULT)
val notificationManager = context!!.getSystemService(NotificationManager::class.java)
notificationManager.createNotificationChannel(notificationChannel)
}
val notifyIntent = Intent(context, MainActivity::class.java).apply {
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
}
val notifyPendingIntent = PendingIntent.getActivity(context, 200, notifyIntent, 0)
val builder: NotificationCompat.Builder = NotificationCompat.Builder(context!!, CHANNEL_ID).apply {
setSmallIcon(R.mipmap.ic_launcher)
setContentTitle(context.getString(R.string.app_name))
setContentText("App ${packageName.substringAfterLast(".")} has been deleted")
priority = NotificationCompat.PRIORITY_DEFAULT
setContentIntent(notifyPendingIntent)
}
with(NotificationManagerCompat.from(context!!)) {
notify(200, builder.build())
}
}
}
MyService
class MyService : Service() {
override fun onBind(intent: Intent?): IBinder? {
return null
}
#RequiresApi(api = Build.VERSION_CODES.N)
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
Log.i("MyLog", "onStartCommand()")
someTask()
return START_STICKY
}
override fun onDestroy() {
super.onDestroy()
Log.i("MyLog", "Service onDestroy()")
val intent = Intent()
intent.action = "servicereload"
intent.setClass(this, MyReceiver::class.java)
this.sendBroadcast(intent)
}
override fun onCreate() {
super.onCreate()
Log.i("MyLog", "Service onCreate()")
}
override fun onTaskRemoved(rootIntent: Intent?) {
val intent = Intent(applicationContext, this.javaClass)
intent.setPackage(packageName)
val pendingIntent = PendingIntent.getService(applicationContext, 1, intent, PendingIntent.FLAG_ONE_SHOT)
val alarmManager = applicationContext.getSystemService(ALARM_SERVICE) as AlarmManager
alarmManager.set(AlarmManager.ELAPSED_REALTIME,1000,pendingIntent)
super.onTaskRemoved(rootIntent)
}
private fun someTask() {
Log.i("MyLog", "Service someTask()")
// val intentFilter = IntentFilter()
// intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED)
// intentFilter.addDataScheme("package")
// registerReceiver(MyReceiver(), intentFilter)
Thread {
for (i in 1..50) {
Log.i("MyLog", "Service i = $i")
try {
TimeUnit.SECONDS.sleep(1)
} catch (e: InterruptedException) {
e.printStackTrace()
}
}
// stopSelf()
}.start()
}
}
someTask() method, just to see if the service is up and running. I check on API 29+ emulators, if I manage to delete the application before 10 seconds, it works well but starts the second service in parallel, which is not good, and I don’t understand why?! If there is nothing to do, after 10 seconds it throws android.app.RemoteServiceException: Context.startForegroundService() did not then call Service.startForeground(): ServiceRecord{ab817c0 u0 com.testappremovel/.MyService} If I remove onDestroy () or onTaskRemoved () in the service, there is no problem with parallel launch, but after 10 seconds it is cut down in any case and, accordingly, does not turn back on. I also have methods for determining the name and icon of the application by package in order to display them in the notification, but of course, when the application is already remote, I cannot get this data. Please tell me, how to do it right, so that everything works as it should?
I am developing a sample app where my goal is to display a notification but initially, just for testing purposes I'm playing an alarm sound when Screen goes ON twice via 4 pressed in the power button. I also intend to run a Service even if the app is totally closed that's why I put the broadcast receiver inside the service.
Before when I implemented this using Service, the app seems to be working fine except for Oreo and above. I found out regarding the execution limit for background, so I updated my code by using Job Intent Service. I just noticed that my broadcast receiver is not being called though it gets registered in the JobIntentService class. I tried playing the alarm sound just on the service (broadcast receiver excluded), and the alarm goes playing, meaning that my Service is functioning properly. I was just wandering why the broadcast receiver is not getting triggered?
This is my code for this:
MainActivity :
class MainActivity : AppCompatActivity() {
private lateinit var receiver: SampleReceiver
private val actionCheck = "action_check"
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
receiver = SampleReceiver()
btnStart.setOnClickListener {
SampleJobIntentService.enqueueWork(
applicationContext,
Intent().setAction(actionCheck)
)
}
}
}
JobIntentService Class:
class SampleJobIntentService : JobIntentService() {
private lateinit var receiver: SampleReceiver
private val actionCheck = "action_check"
companion object {
fun enqueueWork(context: Context, intent: Intent) {
enqueueWork(context, SampleJobIntentService::class.java, 123, intent)
}
}
override fun onHandleWork(intent: Intent) {
Log.v("Service", "Service is running")
receiver = SampleReceiver()
when (intent.action) {
actionCheck -> {
IntentFilter(Intent.ACTION_SCREEN_ON).also { filter ->
this.registerReceiver(receiver, filter)
}
}
}
}
override fun onDestroy() {
unregisterReceiver(receiver)
super.onDestroy()
Log.v("Receiver", "Receiver is now unregistered...")
}
}
Receiver class:
class SampleReceiver : BroadcastReceiver() {
private lateinit var player: MediaPlayer
private var pressedCounts = 0
override fun onReceive(context: Context?, intent: Intent?) {
when (intent?.action) {
Intent.ACTION_SCREEN_ON -> {
pressedCounts =+ 1
if (pressedCounts == 2) {
player.start()
}
}
}
}
}
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.samplereceiver">
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<service
android:name=".SampleJobIntentService"
android:exported="false"
android:permission="android.permission.BIND_JOB_SERVICE">
<intent-filter>
<action android:name="android.intent.action.SCREEN_OFF" />
<action android:name="android.intent.action.SCREEN_ON" />
</intent-filter>
</service>
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
I try using JobSchedulers for my chat app (for async send message):
val job = dispatcher.newJobBuilder()
.setService(BackgroundJobService::class.java)
.setTag(BackgroundJobService.TASKTAG_SEND_MESSAGE)
.setReplaceCurrent(false)
.setConstraints(Constraint.ON_ANY_NETWORK)
.setExtras(bundle)
.setTrigger(Trigger.executionWindow(0, 1))
.build()
dispatcher.mustSchedule(job)
And add my service in manifest:
<service
android:exported="false"
android:name=".data.background.service.BackgroundJobService">
<intent-filter>
<action android:name="com.firebase.jobdispatcher.ACTION_EXECUTE"/>
</intent-filter>
</service>
I write this JobService and it not called onCreate() and not called onDestroy()
class BackgroundJobService : JobService() {
companion object {
val TASKTAG_SEND_MESSAGE = "send_message"
}
#Inject
lateinit var webSocket: IRxWebSocket
var subscribe: Disposable? = null
override fun onCreate() {
super.onCreate()
App.appComponent.inject(this)
subscribe = webSocket.connect().subscribe({}, {})
}
override fun onStartJob(job: JobParameters?): Boolean {
return true // Debug point here
}
override fun onStopJob(job: JobParameters?): Boolean {
return true
}
override fun onDestroy() {
super.onDestroy()
subscribe?.dispose()
}
}
But my onStartJob not calling! Where is my mistake?
Something i see message "Google Play services has stopped".
Your manifest declaration is wrong: you need to declare job services as requiring a specific permission that only the OS itself can use. From the JobService documentation:
Job services must be protected with this permission:
<service android:name="MyJobService"
android:permission="android.permission.BIND_JOB_SERVICE" >
If a job service is declared in the manifest but not protected with this permission, that service will be ignored by the OS.
I must put in bundle with
bundle.putString("TAG", gson.toJson(object))
but not
bundle.putParcelable("TAG", object)