stop service in BroadcastReceiver - java

I got some problems in android studio. I would like to use stopService() to close my service, but its not working.
Here is my project going
click button in MainActivity.java and Start Service Service_Record.class
cardView_Start.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
startService(new Intent(this,Service_Record.class));
}
});
2-1. create notification in Service_Record.class(Service) onCreate()
//step 4 create action
intent_sleep=new Intent(Service_Record.this,Service_RecordData.class);
intent_sleep.setAction("stop");
PendingIntent pendingIntent_sleep =
PendingIntent.getBroadcast(Service_Record.this,1,intent_sleep,PendingIntent.FLAG_UPDATE_CURRENT);
//step1 create channel
createNotificationChannel();
notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
//step2 setting context
builder = new NotificationCompat.Builder(this, "channel_Sleep")
.setSmallIcon(R.drawable.rec)
.setContentTitle("Recording")
.setContentText("It is recording.Press stop button when you awake.")
.setStyle(new NotificationCompat.BigTextStyle()
.bigText("It is recording.Press stop button when you awake."))
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
.addAction(R.drawable.stop,"Stop",pendingIntent_sleep)
.setOngoing(true);
//step3 create
notificationManager.notify(0,builder.build());
2-2. upload value to firebase for every 10 secs in Service_Record.class(Service) onCreate()
if(timer!=null){
timer.purge();
timer.cancel();
}
timer=new Timer();
TimerTask timerTask=new TimerTask() {
#Override
public void run() {
insertDot();
}
};
timer.schedule(timerTask,0,10000);
close service by clicking notification's button in Service_RecordData.java (receiver)
public class Service_RecordData extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
NotificationManager mNotificationManager =
(NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
if (action != null) {
if (action.equals("stop")) {
mNotificationManager.cancel(0);
//Something wrong
context.stopService(new Intent(context,Service_Record.class));
}
}
}
}
Mainfest.xml
<receiver android:name=".Service_RecordData" />
<service android:name=".Service_Record"/>
I found out the problem since my firebase kept uploading value after I closed the notification and APP. Thanks for helping.

OK, I found how to fix it. But I still can't figure out the problem. If anyone know what happened, I'll give you the mark. THX.
context.stopService(new Intent(context,Service_Record.class));
into
Intent intent_service = new Intent(context,Service_Record.class);
context.stopService(intent_service);

Related

How to save and "replay" a notification on Android?

Edit with an update at the bottom with the cause, but still no fix
I am trying to capture a notification and later replay it once I dismiss it. From what I've been able to figure out so far, I can capture a notification, but when I try create a new notification using NotificationManager.notify(), nothing happens. No errors, nothing. Is this even something I should be able to do?
Maybe I am not taking the right approach and someone can suggest a better approach. Like I stated above, I want to be able to know when a user receives a notification and to capture the notification in its entirety, so even when it's dismissed, I can restore it. Maybe there is a way to restore things from the notification history but I haven't been able to figure out fully how that works yet. Here's the code I have so far. I can successfully listen to when a notification is posted or removed. The goal is to send a broadcast when a notification is posted with the notification id and the actual Notification itself (this part works I think), and when the button is pressed, recreate the notification. When I press the button, nothing happens.
public class MainActivity extends AppCompatActivity {
private int notification_id = -1;
private Notification myNotify;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main3);
final Button button = findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Bundle extras = myNotify.extras;
String title = extras.getString("android.title");
String text = extras.getString("android.text");
NotificationManager nManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
nManager.notify(notification_id, myNotify);
}
});
}
private MyBroadcastReceiver myReceiver;
#Override
public void onResume() {
super.onResume();
myReceiver = new MyBroadcastReceiver();
final IntentFilter intentFilter = new IntentFilter("notification_restore");
LocalBroadcastManager.getInstance(this).registerReceiver(myReceiver, intentFilter);
}
#Override
public void onDestroy() {
super.onDestroy();
if (myReceiver != null)
LocalBroadcastManager.getInstance(this).unregisterReceiver(myReceiver);
myReceiver = null;
}
public class MyBroadcastReceiver extends BroadcastReceiver {
#Override
#Nullable
public void onReceive(Context context, Intent intent) {
// Here you have the received broadcast
// And if you added extras to the intent get them here too
// this needs some null checks
Bundle b = intent.getExtras();
notification_id = b.getInt("notification_id");
myNotify = b.getParcelable("notification");
}
}
}
public class MyNotificationListenerService extends NotificationListenerService {
private int notification_id;
private Notification myNotify;
#Override
public void onNotificationPosted(StatusBarNotification sbn) {
if ((sbn.getNotification().flags & Notification.FLAG_GROUP_SUMMARY) != 0) {
//Ignore the notification
return;
}
notification_id = sbn.getId();
myNotify = sbn.getNotification();
Intent intent = new Intent("notification_restore");
Bundle b = new Bundle();
b.putInt("notification_id", notification_id);
b.putParcelable("notification", myNotify);
intent.putExtras(b);
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
}
#Override
public void onNotificationRemoved(StatusBarNotification sbn) {
if ((sbn.getNotification().flags & Notification.FLAG_GROUP_SUMMARY) != 0) {
//Ignore the notification
return;
}
}
}
Edit:
So it looks like the reason my notification isn't showing up is because it complains about not finding a channel, even though the notification I am trying to replay has one. The exact error is:
E/NotificationService: No Channel found for pkg=com.gevdev.notify, channelId=bugle_default_channel, id=0, tag=null, opPkg=com.gevdev.notify, callingUid=10086, userId=0, incomingUserId=0, notificationUid=10086, notification=Notification(channel=bugle_default_channel pri=1 contentView=null vibrate=null sound=null tick defaults=0x0 flags=0x10 color=0xff2a56c6 category=msg groupKey=bugle_notification_group_key sortKey=00 actions=2 vis=PRIVATE)
I am still new to android, but my initial guess is that the channelId found bugle_default_channel isn't found under my package name, but I don't know how to fix this yet.
Figured it out
Even though the notification that I am grabbing to replay has a channel ID, the NotificationManager doesn't have that notification channel registered. I figured it based off the code found here. This is how to register it.
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
NotificationChannel notificationChannel = nManager.getNotificationChannel(myNotify.getChannelId());
if (notificationChannel == null) {
int importance = NotificationManager.IMPORTANCE_HIGH;
notificationChannel = new NotificationChannel(myNotify.getChannelId(), "Description Goes Here", importance);
notificationChannel.setLightColor(Color.GREEN);
notificationChannel.enableVibration(true);
nManager.createNotificationChannel(notificationChannel);\
}
}

Notification doesn't appear to android 8+

With this code, I want to click in a button and appear a notification. The problem is when in click in my button doesn't appear when I test in emulator api 26+. In api below 26 appear normally without problems.
btNotify.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
notification();
}
});
public void notification() {
RemoteViews remoteViews = new
RemoteViews(getApplicationContext().getPackageName(),R.layout.notification_collapsed);
remoteViews.setTextViewText(R.id.title, "Atividade");
remoteViews.setTextViewText(R.id.act, activity);
remoteViews.setChronometer(R.id.timer, chronometer.getBase(), chronometer.getFormat(), !running);
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, "notification")
.setSmallIcon(R.drawable.ic_baseline_access_time_24)
.setContent(remoteViews)
.setPriority(NotificationCompat.PRIORITY_DEFAULT);
NotificationManager notifManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
assert notifManager != null;
notifManager.notify(1, builder.build());
}

BroadcastReceiver doesn't work for the second time

I'm trying to schedule notifications with AlarmManager It works perfectly when I schedule one notification but when I schedule two notification, the first notification is okay but the second one not works.
I figured out opening the app after few minutes will notify the second notification. I think something is wrong with my BroadcastReceiver
MainActivity.java
Intent intent = new Intent(context,NotificationClass.class);
intent.putExtra("notification_id", id);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context,id,intent,PendingIntent.FLAG_UPDATE_CURRENT);
alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(),pendingIntent);
Notification.java
public class NotificationClass extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
int id = intent.getIntExtra("notification_id",0);
NotificationCompat.Builder builder = new NotificationCompat.Builder(context,"1")
.setContentTitle("Notification")
.setContentText("Content")
.setSmallIcon(R.drawable.notif_ic);
Notification notification = builder.build();
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context);
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel("1","test", NotificationManager.IMPORTANCE_HIGH);
notificationManager.createNotificationChannel(channel);
}
notificationManager.notify(id,notification);
}
AndroidManifest.xml
<receiver android:name=".NotificationClass" ></receiver>
I don't know what is wrong with my code. Can anybody help me with this?
Broadcast receiver to receive the data:
private BroadcastReceiver mReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String alertMessage = intent.getStringExtra("type");
doNotificationAlertWorkHere(alertMessage);
}
};
Register & Unregister your broadcast to avoid static leaks.
via the Android manifest file. (Statically)
<receiver android:name="YourBroadcastReceiverName"> </receiver>
via the Context.registerReceiver() and Context.unregisterReceiver() methods. (Dynamically)
#Override
protected void onPause() {
super.onPause();
// unregister broadcast
LocalBroadcastManager.getInstance(this).unregisterReceiver(mReceiver);
}
#Override
protected void onResume() {
super.onResume();
// register broadcast
IntentFilter filter = new IntentFilter(Constants.ACTION);
LocalBroadcastManager.getInstance(this).registerReceiver(mReceiver, filter);
}
Send Broadcast like:
// public static final String ACTION = "ALERT";
Intent intent = new Intent(Constants.ACTION);
intent.putExtra("type", "SUP BRO. Stay Inside");
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
Knowledge Note :- Broadcast receiver is like a Cannon-fire to score a hit, you have to determine what to fire (eg. msg), where to fire (eg. activity). Load & unload the cannon to score another hit. (eg. Register & Unregister)
I have tried it and it is working. Add your notification code inside onReceive.
Broadcast Receiver
class AlarmReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
/*
Your implementation
*/
}
}
Mainfest
<receiver
android:name=".AlarmReceiver"
android:exported="true"
android:enabled="true" />
Creating pending intents
val alarmManager = activity.getSystemService(Activity.ALARM_SERVICE) as AlarmManager
val alarmIntent = Intent(activity.applicationContext, AlarmReceiver::class.java) // AlarmReceiver1 = broadcast receiver
val calendar = Calendar.getInstance()
calendar.timeInMillis = timeInMilliSeconds
val pendingIntent = PendingIntent.getBroadcast(activity, timeInMilliSeconds.toInt(), alarmIntent, PendingIntent.FLAG_CANCEL_CURRENT)
alarmManager.set(AlarmManager.RTC_WAKEUP, calendar.timeInMillis, pendingIntent)
First, make sure your notification Id is difference every single time you create a notification
Second, you miss tag intent-filter inside tag receive in manifest. pls check this https://developer.android.com/guide/components/broadcasts.
Hope this help!

IntentService not working

I am building an application whereby the notification will ring at a specific time and after which disappear if it is left unattended for 15 minutes. It works when i plug in my device and runs the code. However, once i unplug my device and runs the app, the notification works but it does not disappear after 15 minutes if it is left unattended. Please advice me how should i run the app like how it does when the device is plug into the computer. Also, it should work when the app is killed.
FYI, i'm using notification, alarmmanager, broadcast receiver and intentservice. Below is the snippet of my codes.
AlarmReceiver.java
public class AlarmReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Notification(context, "Wifi Connection On");
Intent background = new Intent(context, BackgroundService.class);
context.startService(background);
}
public void Notification(final Context context, String message) {
// notification codes
}
}
BackgroundService.java
public class BackgroundService extends IntentService {
public BackgroundService() {
super("BackgroundService");
}
#Override
protected void onHandleIntent(Intent intent) {
//countdown 15 minutes and cancel notification automatically
Timer timer=new Timer();
TimerTask task=new TimerTask() {
#Override
public void run() {
// Create Notification Manager
NotificationManager notificationmanager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
// Dismiss Notification
notificationmanager.cancelAll();
}
};
timer.schedule(task, 900000);
}
}
Manifest.xml
<receiver android:name=".AlarmReceiver" android:process=":remote" />
<service android:name=".BackgroundService" />
Please provide me some suggestions. Thank you.
This service will run twice: first time it does nothing except rescheduling, second time it cancels notifications.
public class BackgroundService extends IntentService {
private static final int REQUEST_CODE = 42;
private static final String ACTION_CANCEL_NOTIFS = "CancelNotifications";
public BackgroundService() {
super("BackgroundService");
}
#Override
protected void onHandleIntent(Intent intent) {
if (intent != null && ACTION_CANCEL_NOTIFS.equals(intent.getAction())) {
NotificationManager notificationmanager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
notificationmanager.cancelAll();
}
else {
reschedule();
}
}
private void reschedule() {
final Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.add(Calendar.MINUTE, 15);
final Intent serviceIntent = new Intent(this, getClass());
serviceIntent.setAction(ACTION_CANCEL_NOTIFS);
PendingIntent pendingIntent = PendingIntent.getService(this, REQUEST_CODE, serviceIntent, PendingIntent.FLAG_UPDATE_CURRENT);
final AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
alarmManager.set(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pendingIntent);
}
}
Explanation:
In your code, I assume, you start your service with startService(new Intent(this, BackgroundService.class)). This intent is passed as a parameter in onHandleIntent(Intent), which means you can access it from inside your service.
Intent allows you to pass additional data, such as action (useful for IntentFilters) or extras. Because you haven't set any, the first time around the execution goes to the else branch of onHandleIntent() method. AlarmManager is then scheduled to run your service in 15 minutes with serviceIntent. Note serviceIntent.setAction(ACTION_CANCEL_NOTIFS). So the second time around the execution goes to the if branch and cancels notifications.
A better approach would be creating a pending intent right from inside your activity instead of starting a service with startService. That would make your service simpler and more cohesive.
Service only runs when CPU is awake. If CPU gets off, service will not run.
SO to make your service to be run if phone goes to sleep, you need to aquire wake lock.
BackgroundService class
public class BackgroundService extends IntentService {
private PowerManager.WakeLock wl;
public BackgroundService() {
super("BackgroundService");
}
#Override
protected void onHandleIntent(Intent intent) {
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "Partial lock permission");
wl.acquire();
//countdown 15 minutes and cancel notification automatically
Timer timer=new Timer();
TimerTask task=new TimerTask() {
#Override
public void run() {
// Create Notification Manager
NotificationManager notificationmanager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
// Dismiss Notification
notificationmanager.cancelAll();
wl.release();
}
};
timer.schedule(task, 900000);
}
}
If this does work out, try to give below permission in Android Manifest file
<uses-permission android:name="android.permission.WAKE_LOCK" />

Keep broadcast receiver running after application is closed

I need to keep broadcast receiver running all the time after app has been started.
Here is the code that registers this receiver in the application
IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON);
filter.addAction(Intent.ACTION_SCREEN_OFF);
BroadcastReceiver mReceiver = new ScreenEventsReceiver();
registerReceiver(mReceiver, filter);
And code for receiver
public class ScreenEventsReceiver extends BroadcastReceiver {
public static boolean wasScreenOn = true;
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
wasScreenOn = false;
Log.d("ScreenEventReceiver", "ON");
} else if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
wasScreenOn = true;
Log.d("ScreenEventReceiver", "ON");
}
}
}
You can use a service
In main app start/stop the service
Intent service = new Intent(context, MyService.class);
context.startService(service);
...
Intent service = new Intent(context, MyService.class);
context.stopService(service);
service
public class MyService extends Service
{
private static BroadcastReceiver m_ScreenOffReceiver;
#Override
public IBinder onBind(Intent arg0)
{
return null;
}
#Override
public void onCreate()
{
registerScreenOffReceiver();
}
#Override
public void onDestroy()
{
unregisterReceiver(m_ScreenOffReceiver);
m_ScreenOffReceiver = null;
}
private void registerScreenOffReceiver()
{
m_ScreenOffReceiver = new BroadcastReceiver()
{
#Override
public void onReceive(Context context, Intent intent)
{
Log.d(TAG, "ACTION_SCREEN_OFF");
// do something, e.g. send Intent to main app
}
};
IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_OFF);
registerReceiver(m_ScreenOffReceiver, filter);
}
}
Accepted answer is not an actual answer i think. I will explain what the issue. I think you are testing your app in the Huawie, Oppo, Vivo, Xiomi,asus....... or some devices. With that devices if we close the application they will also close our broadcast receivers. So thats the problem.(To check that use a with pixel nexus emulator). I will explain how to resolve this.``
we would add our app to the protected app list. OS only allow to them to continue broadcast receiver activities.(Copy this array declaration to your code)
private static final Intent[] POWERMANAGER_INTENTS = {
new Intent().setComponent(new ComponentName("com.miui.securitycenter", "com.miui.permcenter.autostart.AutoStartManagementActivity")),
new Intent().setComponent(new ComponentName("com.letv.android.letvsafe", "com.letv.android.letvsafe.AutobootManageActivity")),
new Intent().setComponent(new ComponentName("com.huawei.systemmanager", "com.huawei.systemmanager.optimize.process.ProtectActivity")),
new Intent().setComponent(new ComponentName("com.huawei.systemmanager", "com.huawei.systemmanager.appcontrol.activity.StartupAppControlActivity")),
new Intent().setComponent(new ComponentName("com.coloros.safecenter", "com.coloros.safecenter.permission.startup.StartupAppListActivity")),
new Intent().setComponent(new ComponentName("com.coloros.safecenter", "com.coloros.safecenter.startupapp.StartupAppListActivity")),
new Intent().setComponent(new ComponentName("com.oppo.safe", "com.oppo.safe.permission.startup.StartupAppListActivity")),
new Intent().setComponent(new ComponentName("com.iqoo.secure", "com.iqoo.secure.ui.phoneoptimize.AddWhiteListActivity")),
new Intent().setComponent(new ComponentName("com.iqoo.secure", "com.iqoo.secure.ui.phoneoptimize.BgStartUpManager")),
new Intent().setComponent(new ComponentName("com.vivo.permissionmanager", "com.vivo.permissionmanager.activity.BgStartUpManagerActivity")),
new Intent().setComponent(new ComponentName("com.samsung.android.lool", "com.samsung.android.sm.ui.battery.BatteryActivity")),
new Intent().setComponent(new ComponentName("com.htc.pitroad", "com.htc.pitroad.landingpage.activity.LandingPageActivity")),
new Intent().setComponent(new ComponentName("com.asus.mobilemanager", "com.asus.mobilemanager.MainActivity"))};
Put these code to your onCreate Method. Here i used shared preference for check it only first time of the app open.
`
final SharedPreferences.Editor pref = getSharedPreferences("allow_notify", MODE_PRIVATE).edit(); pref.apply(); final SharedPreferences sp = getSharedPreferences("allow_notify", MODE_PRIVATE)`;
if(!sp.getBoolean("protected",false)) {
for (final Intent intent : POWERMANAGER_INTENTS)
if (getPackageManager().resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY) != null) {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("Alert Title").setMessage("Alert Body")
.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialogInterface, int i) {
startActivity(intent);
sp.edit().putBoolean("protected",true).apply();
}
})
.setCancelable(false)
.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
}
})
.create().show();
break;
Be careful if you are using Android 4.4.x as there is a bug which kills background services when closing the app. I was testing my app in Android 4.4.2 and I had the same problem. Here there is a detailed explanation:
http://www.androidpolice.com/2014/03/07/bug-watch-stopping-apps-on-android-4-4-2-can-silently-kill-related-background-services-a-fix-is-on-the-way/
You cannot receive some broadcast events through components declared in manifest.
These events are
ACTION_BATTERY_CHANGED
ACTION_CONFIGURATION_CHANGED
ACTION_SCREEN_OFF (You are playing with this event)
ACTION_SCREEN_ON (You are playing with this event)
ACTION_TIME_TICK
Reference https://developer.android.com/reference/android/content/Intent.html#ACTION_SCREEN_ON
So in your specific events,
you will have to create a Service & you will have to register your event explicitly in service onCreate() with with Context.registerReceiver().
For other events,
entry in manifest is sufficient.
If you declare BroadcastReceiver in the Manifest, it will always be active and be called even if the application is closed/stopped
You could start a service that is running in the foreground. That's the only way to ensure (mostly) that your app will get the events. There is still a chance that your foreground service could get killed in times of crazy memory pressure from the OS (so it's not foolproof). If you start a service in the foreground, the user will see a persistent notification to know that it is always running, though.
So the moral of the story is, do you really need to monitor the screen off/on events at all times? The reason that they force you to register a receiver not in the manifest is that they don't want people to always be monitoring these events and slowing down the device. What are you trying to accomplish?
The best way I found is the Foreground Services. I registered my BroadcastReceiver from my Service only under the onStartCommand() as I want my service needs to run always, I returned START_STICKY
This way, my broadcast receiver survives even after terminating the app from stack.
Used below code in my service
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i("rht", "Received start id " + startId + ": " + intent);
String input = intent.getStringExtra("inputExtra");
createNotificationChannel();
Intent notificationIntent = new Intent(this, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this,
0, notificationIntent, 0);
Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
.setContentTitle("Foreground Service")
.setContentText(input)
.setSmallIcon(R.drawable.ic_launcher_background)
.setContentIntent(pendingIntent)
.build();
startForeground(1, notification);
}
This is how I started my service
Intent serviceIntent = new Intent(this, SpeechServiceForeground.class);
ContextCompat.startForegroundService(this, serviceIntent);

Categories

Resources