I understand that a Service class runs in the background in Android and I also understand how to start and stop a service.
I am just trying to get a better idea of how to use a Service.
So say I have a service running in the background. How can I simply get the URL name of a webpage from a web browser app.
Her is my service below:
public class MyService extends Service {
private static final int NOTIF_ID = 1;
private static final String NOTIF_CHANNEL_ID = "Channel_Id";
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
// do your jobs here
startForeground();
return super.onStartCommand(intent, flags, startId);
}
private void startForeground() {
Intent notificationIntent = new Intent(this, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,
notificationIntent, 0);
startForeground(NOTIF_ID, new NotificationCompat.Builder(this,
NOTIF_CHANNEL_ID) // Create a Notification Channel
.setOngoing(true)
.setSmallIcon(R.drawable.ic_launcher_background)
.setContentTitle(getString(R.string.runningtitle))
.setContentText(getString(R.string.runningtext))
.setContentIntent(pendingIntent)
.build());
}
}
Related
Please be informed, we are trying to start activity from service class, which is fired on clicking push notification addaction intent. The service class contains two actions, one to stop playing ringtone and another to startactivity. But unfortunately the start activity just does not boot in our service class.
Service Class page is as given below:
public class RingtonePlayingService extends Service {
private static final String TAG = RingtonePlayingService.class.getSimpleName();
private static final String URI_BASE = RingtonePlayingService.class.getName() + ".";
public static final String ACTION_DISMISS = URI_BASE + "ACTION_DISMISS";
public static final String ACTION_START = URI_BASE + "ACTION_START";
private MediaPlayer mp;
private Ringtone ringtone;
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG, "onStartCommand");
int notificationId = intent.getIntExtra("notificationId", 0);
if (intent == null) {
Log.d(TAG, "The intent is null.");
return START_REDELIVER_INTENT;
}
String action = intent.getAction();
if (ACTION_START.equals(action)) {
String uri = String.valueOf(intent.getIntExtra("uri", 0));
Intent intents = new Intent(this, MainActivity.class);
intents.putExtra("uri", uri);
intents.putExtra("notification_id", notificationId);
intents.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
this.startActivity(intents);
}
return START_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
mp.reset ();
}}
Firebase (from where service class's intent is fired)
Intent startIntent = new Intent(this, RingtonePlayingService.class);
startIntent.setAction(RingtonePlayingService.ACTION_START);
startIntent.putExtra("uri", uri);
startIntent.putExtra("notification_id", notification_id);
PendingIntent pt = PendingIntent.getService(this,123, startIntent, PendingIntent.FLAG_UPDATE_CURRENT);
NotificationCompat.Action action_n = new NotificationCompat.Action.Builder(R.mipmap.ic_launcher, tag, pt).build();
The objective here is on firing of pending Intent 'pt'. We want to start the activity (that opens the app's url) as well as run the service class (which stops the service and the ringtone).
Please help us find a solution on this never ending issue.
The service class contains two actions, one to stop playing ringtone and another to startactivity. But unfortunately the start activity just does not boot in our service class.
You cannot start an activity from the background on modern versions of Android.
Firebase (from where service class's intent is fired)
That code has problems:
Your Intent is for RingtonePlayingService, which according to your first code snippet is a Service. Yet, you try using it with PendingIntent.getActivity(), rather than PendingIntent.getService().
You are using addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK), which are irrelevant for a Service.
This question already has answers here:
How can we prevent a Service from being killed by OS?
(11 answers)
Background service stops after 20 sec after destroy app in Android 10 java
(1 answer)
Closed 1 year ago.
I am running audio player service but If I put my phone on sleep the player stops or the background service I don't know what's the problem.
this is my music service class :
public class MusicService extends Service {
public static final String ACTION_NEXT = "NEXT";
public static final String ACTION_PREV = "PREVIOUS";
public static final String ACTION_PLAY = "PLAY";
public static final String ACTION_FORWARD = "FORWARD";
public static final String ACTION_REWIND = "REWIND";
public static final String ACTION_CONTINUE = "CONTINUE";
ActionPlaying actionPlaying;
Action action;
private final IBinder mBinder = new MyBinder();
#Nullable
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
public class MyBinder extends Binder {
MusicService getService() {
return MusicService.this;
}
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
String actionName = intent.getStringExtra("myActionName");
if (actionName != null) {
switch (actionName)
{
case ACTION_PLAY:
if(actionPlaying!= null){
if(action!= null){
actionPlaying.playClicked();
action.playPauseClicked();
}}
break;
case ACTION_NEXT:
if(actionPlaying != null){
actionPlaying.nextClicked();
}
break;
case ACTION_PREV:
if(actionPlaying != null){
actionPlaying.prevClicked();
}
break;
case ACTION_FORWARD:
if(actionPlaying != null){
actionPlaying.forwardClicked();
}
break;
case ACTION_REWIND:
if(actionPlaying != null){
actionPlaying.rewindClicked();
}
break;
case ACTION_CONTINUE:
Toast.makeText(this, "continue", Toast.LENGTH_SHORT).show();
action.continueMediaPlayer();
}
}
return START_STICKY;
}
public void setCallBack(ActionPlaying actionPlaying){
this.actionPlaying = actionPlaying;
}
public void setCallBack(Action action) {
this.action = action;
}
public void onTaskRemoved(Intent rootIntent) {
super.onTaskRemoved(rootIntent);
notificationManager.cancelAll();
saveData();
simpleExoPlayer.release();
}
}
and this is my media player initialization :
public void prepareMedia() {
isPlaying=true;
simpleExoPlayer = new SimpleExoPlayer.Builder(MediaPlayer_Activity.this).build();
MediaItem mediaItem = MediaItem.fromUri(audioUrl);
simpleExoPlayer.addMediaItem(mediaItem);
simpleExoPlayer.prepare();
simpleExoPlayer.seekTo(songPrevPosition);
}
Please tell me what's wrong LogCat is not showing anything I don't know how to stop this and where the problem is....
please help
After 9 Android version we have protections for simple service. Simple service can live 10 seconds, no more. You need to declare you service as Foreground Service. It will look like notification in status bar.
For fully information read documentation
according to Android Developers documentation :
You need to upgrade your background process to foreground inorder to make it live without needing your application to be visible to the user.
in order to change your service to foreground one, your service need to have a notification to inform the user that your music player service is working.
a simple foreground service code might look like this :
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
Notification notification = buildStartingNotification();
startForeground(startId, notification);
...
return START_STICKY;
}
private Notification buildStartingNotification() {
int priority =NotificationCompat.PRIORITY_LOW;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
priority = NotificationManager.IMPORTANCE_LOW;
createNotificationChannel(priority);
}
Notification notification =
new Notification.Builder(this,CHANNEL_ID)
.setContentTitle("Your_notification_title")
.setContentText("Your_notification_description ")
.setSmallIcon(R.drawable.icon)
.setPriority(priority)
.build();
}
#RequiresApi(api = Build.VERSION_CODES.O)
private void createNotificationChannel(int priority) {
CharSequence name = getText("Your_Channel_Name");
String description = getString("Your_Channel_Desc");
NotificationChannel channel = new NotificationChannel(CHANNEL_ID, name, priority);
channel.setDescription(description);
NotificationManager notificationManager = getSystemService(NotificationManager.class);
notificationManager.createNotificationChannel(channel);
}
N.B : if you're using application with (target_api > 26) you need to have also a notification channel which I included its code in createNotificationChannel, where your CHANNEL_ID could be any unique string id you want.
if you're wandering what's the meaning of notification channel ?
a notification channel is a mechanism built for android 8 or later to make the user turn off/on group of notification with same channel at once from setting.
as an example your application might have multiple notification channels (news/games/entertainment...etc), then the user can turn off news &games and leave only entertainment on.
First of all make sure you use foreground service. I suggest to you to start permanent notification like this:
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
NotificationChannel channel;
Intent notifyIntent = new Intent(this, SomeActivity.class);
notifyIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
PendingIntent notifyPendingIntent = PendingIntent.getActivity(this, 0, notifyIntent, PendingIntent.FLAG_UPDATE_CURRENT);
Notification notification = showStableMessage(this,
getString(R.string.app_desc),
"Message to user",
R.mipmap.ic_icon,
notifyPendingIntent);
startForeground(NotificationUtil.STABLE_CHANNEL_NOTIFY_ID, notification);
return Service.START_STICKY;
}
private Notification showStableMessage(Context context, String title, String message, int icon, PendingIntent intent) {
NotificationChannel channel;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
channel = new NotificationChannel(STABLE_CHANNEL_ID,
STABLE_CHANNEL_NAME, NotificationManager.IMPORTANCE_DEFAULT);
channel.enableLights(true);
((NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE)).createNotificationChannel(channel);
}
Notification notification = new NotificationCompat.Builder(context, STABLE_CHANNEL_ID)
.setContentTitle(title)
.setContentText(Html.fromHtml(message)).setPriority(PRIORITY_DEFAULT)
.setSmallIcon(icon)
.setSound(Settings.System.DEFAULT_NOTIFICATION_URI)
.setContentIntent(intent)
.setCategory(NotificationCompat.CATEGORY_SERVICE).build();
notification.defaults |= Notification.DEFAULT_VIBRATE;
return notification;
}
Second you have to put this in manifest:
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<application
.....>
<service
android:name=".data.service.MyService"
android:foregroundServiceType="mediaPlayback"
android:enabled="true"/>
</application>
I'm building an android service for audio playback (it's a flutter app using native code for playback), but when launching the service it doesn't seem to run onCreate() and `onStartCommand()'.
I've tested it with putting some print or log statements in those functions, but they never run. I've also made sure to add the service into the AndroidManifest.xml
Here is how I launch the service:
public class MainActivity extends FlutterActivity implements MethodCallHandler {
public void onMethodCall(MethodCall call, Result result) {
switch (call.method) {
[...]
case "startService":
Intent serviceIntent = new Intent(getFlutterView().getContext(), AudioService.class);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
this.startForegroundService(serviceIntent);
} else {
this.startService(serviceIntent);
}
break;
[...]
}
}
FlutterActivity is a class that extends Activity
Here is the service class:
public class AudioService extends Service {
public MediaPlayer audioPlayer;
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
super.onCreate();
Log.i("Audio", "onCreate()");
}
#Nullable
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
Log.i("Audio", "Starting service...");
// create notification
Intent notificationIntent = new Intent(this, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(
this,
0,
notificationIntent,
0
);
Notification audioNotification = new NotificationCompat.Builder(this, CHANNEL_ID)
.setContentTitle("Foreground service is running")
.setContentText("This notification does nothing")
.setSmallIcon(R.drawable.app_icon)
.setContentIntent(pendingIntent)
.build();
startForeground(1, audioNotification);
audioPlayer = new MediaPlayer();
Log.i("Audio", "Service started successfuly");
return START_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
// destroy the player
stopAudio();
}
[...]
}
And the service declaration in AndroidManifest:
<service
android:name=".AudioService"
android:process="net.tailosive.app.AudioService"
android:enabled="true"
android:exported="true"/>
I don't see what I'm doing wrong here.
A thing worth mentioning is that the installed package name is net.tailosive.app, but the the package name included in java files, directories and manifest is com.example.tailosive. Could this be an issue?
I highly recommend reading this topic : Context.startForegroundService() did not then call Service.startForeground()
From my experience (Working on the same scenario), you will face lots of unexpected bugs on different devices and different SDK versions by starting a Foreground Service using startForegroundService command. Just use the old startService method and you'll be fine.
Also what's the purpose of using START_STICKY while it's a Foreground Service and it's guaranteed to be running as long as the ongoing notification displays?
I have an Activity where the user can download a video. Upon user's click, the Download Service starts to download the content.
There is a progress bar in the Activity UI which I would like to update according to download progress in the service which broadcasts the progress periodically.
Everything works fine but after a certain time the service stops sending any broadcast progress, hence, the UI does not update anymore.
Additionally, how I can resume receiving the progress broadcast when the user goes to another Activity and comes back to this Activity? I mean, even if the above issue is solved, when the user presses back button and go to other activity and comes back to this activity, the progress gets lots. How can I check for any existing broadcast and receive it whenever the user comes to this activity.
In the ACTIVITY:
private BroadcastReceiver receiver = new BroadcastReceiver() {
#Override public void onReceive(Context context, Intent intent) {
Bundle bundle = intent.getExtras();
if (bundle != null) {
Log.d("DownloadService", "Progress Received In Activity");
Double progress = bundle.getDouble("PROGRESS");
updateDownloadProgressBar(progress);
}
}
};
private void startDownloadService() {
final String videoId = mItem.getAttributes().get(KEY_ASSET_ID);
Intent intent = new Intent(this, DownloadService.class);
intent.putExtra("VIDEOID", videoId);
startService(intent);
}
in the onResume():
registerReceiver(receiver, new IntentFilter(DownloadService.NOTIFICATION_SERVICE));
in the onPause():
unregisterReceiver(receiver);
In the SERVICE:
private void publishProgress(double progress) {
Log.d(TAG, "Broadcasting progress from Service");
Intent intent = new Intent(NOTIFICATION_SERVICE);
intent.putExtra("PROGRESS", progress);
sendBroadcast(intent);
}
The download and progress work fine to 38% then stop.
It seems that the service is being stopped/killed from the OS, to avoid that use foreground service so you can make sure it will not be killed from the OS.
See the sample code below:
Service
public class PendingService extends Service {
private final static String TAG = "PendingService";
public final static int NOTIFICATION_ID = 94;
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
startInForeground();
// Do your work here ...
return START_STICKY;
}
private void startInForeground() {
String NOTIFICATION_CHANNEL_ID = "default";
String NOTIFICATION_CHANNEL_NAME = "My Pending Service";
String NOTIFICATION_CHANNEL_DESC = "This notification holding a pending task";
Intent notificationIntent = new Intent(this, SplashActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID)
.setSmallIcon(R.drawable.notification)
.setOngoing(true)
.setAutoCancel(true)
.setContentIntent(pendingIntent);
if (Build.VERSION.SDK_INT >= 26) {
NotificationChannel channel = new NotificationChannel(NOTIFICATION_CHANNEL_ID, NOTIFICATION_CHANNEL_NAME, NotificationManager.IMPORTANCE_LOW);
channel.setDescription(NOTIFICATION_CHANNEL_DESC);
channel.setSound(null, null);
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
if (notificationManager != null) {
notificationManager.createNotificationChannel(channel);
}
}
Notification notification = builder.build();
startForeground(NOTIFICATION_ID, notification);
}
#Override
public void onDestroy() {
super.onDestroy();
removeNotification(NOTIFICATION_ID);
// ....
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
private void removeNotification(int notificationId) {
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
if (notificationManager != null) {
notificationManager.cancel(notificationId);
}
}
}
Utils you may need
class ServiceUtils {
/**
* #param service: Service to run
*/
fun startService(context: Context, service: Class<out Service>) {
val serviceIntent = Intent(context, service)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
context.startForegroundService(serviceIntent)
} else {
context.startService(serviceIntent)
}
}
/**
* #return True: if the service is running
*/
fun isServiceRunning(context: Context, serviceClass: Class<*>): Boolean {
val manager = context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
for (service in manager.getRunningServices(Integer.MAX_VALUE)) {
if (serviceClass.name == service.service.className) {
return true
}
}
return false
}
}
Am Working on a timer based app where the notification shows up when the timer starts to run. I have set it as ongoing so that it cannot be cleared.
I have used cancelAll() method for some cases which works fine but when I force close the app, the notification still shows up and cannot be removed and tried to use the method in onDestroy() method still the problem prevails.
Here is my code and created the channel in another class :
public void sendNotif(){
Intent resultIntent = new Intent(this, TimerActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, resultIntent, PendingIntent.FLAG_UPDATE_CURRENT);
not = new NotificationCompat.Builder(this,Notif.CHANNEL_ID)
.setSmallIcon(R.drawable.curved_shape)
.setContentTitle("Productivity Timer")
.setContentText("Your Timer is Running")
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setCategory(NotificationCompat.CATEGORY_PROGRESS)
.setOngoing(true)
.setContentIntent(pendingIntent)
.build();
notificationManager.notify(1,not);
}
I found this great solution once, I will retype it here
Since your application and the notification are handled in different threads, so killing your application won't kill the notification. The solution is to create a Service to kill notification, since services will restart themselves when the app is killed suddenly, you can use the automatic restart to kill the notification.
Create the service class
public class KillNotificationsService extends Service {
public class KillBinder extends Binder {
public final Service service;
public KillBinder(Service service) {
this.service = service;
}
}
public static int NOTIFICATION_ID = 666;
private NotificationManager mNM;
private final IBinder mBinder = new KillBinder(this);
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return Service.START_STICKY;
}
#Override
public void onCreate() {
mNM = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
mNM.cancel(NOTIFICATION_ID);
}
}
Add it to your manifest
<service android:name="KillNotificationsService"></service>
Always create the Service before fireing the notification, and use the static notificationid
ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className,
IBinder binder) {
((KillBinder) binder).service.startService(new Intent(
MainActivity.this, KillNotificationsService.class));
Notification notification = new Notification(
R.drawable.ic_launcher, "Text",
System.currentTimeMillis());
Intent notificationIntent = new Intent(MainActivity.this,
Place.class);
PendingIntent contentIntent = PendingIntent.getActivity(
MainActivity.this, 0, notificationIntent, 0);
notification.setLatestEventInfo(getApplicationContext(),
"Text", "Text", contentIntent);
NotificationManager mNM = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
mNM.notify(KillNotificationsService.NOTIFICATION_ID,
notification);
}
public void onServiceDisconnected(ComponentName className) {
}
};
bindService(new Intent(MainActivity.this,
KillNotificationsService.class), mConnection,
Context.BIND_AUTO_CREATE);