How to create a Notification or Toast from startup service? - java

I'm working on an basic reminder application which has a user interface capable to log user set dates to an sqlite database. To complete my application I'd like to have a service which starts and keep running in the background when the phone is restarted, so I can periodically check the database and display a notification message to the user if any of the dates are close.
I can start my service on startup (I can send LOG messages to Android Studio) but I can't display notifications. It seems the examples I have found always rely on an activity, but how would I have an activity without having the main app running? (and ofcourse thats the point of my background service, the user doesnt have to open the main app).
Q1: How can I display a Toast message from this service?
Q2: How can I display a notification from this service?
public class autostartservice extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) {
for (int i = 0; i < 40; i++) {
synchronized (this) {
try {
wait(1000);
} catch (Exception e) {}
Log.i("myDebug", "Just wait here couple second until the phone boots all the way");
}
}
Toast.makeText(context, "Look at this Toast! Cool uh?", Toast.LENGTH_SHORT).show();
}
}
}

All these kind of things uses a Context to show a Toast or a Notification. A Service "acts as" a Context, so you can do quite the same things as you do in an Activity. You only have to pay attention that a normal Service runs in the same Thread of the UserInterface, so if the Service is blocking (waiting some event in a Blocking way) even the UserInterface is blocked and Notifications or Toasts cannot be displayed while blocked/frozen.

Related

Can a homescreen widget BroadcastReceiver listen for phone events?

I am trying to update my homescreen widget when there is a Do not Disturb change. Because WidgetProvider is a BroadcastReceiver in itself, I thought it would be simple. But I am not seeing any Toast when I switch Dnd on or off. Does it mean that the WidgetProvider can only send broadcasts but not receive them?
Here is my code:
#Override
public void onReceive(Context context, Intent intent) {
super.onReceive(context, intent);
String action = intent.getAction();
assert action != null;
if (action.equals(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED)) {
System.out.println("Success!");
}
}
You do not show how you are registering for that broadcast. If it is in the manifest, the broadcast that you are trying to receive is not listed on the implicit broadcast exceptions "whitelist", so you may not receive it on Android 8.0+. The only way that you would be able to receive that broadcast on Android 8.0+ is if you have a foreground service running all the time, and that has costs.
Also:
I am not familiar with that specific broadcast and so I am uncertain if it is sent on a DND change (though it certainly seems plausible)
You are not showing a Toast; instead, you are printing a message to stdout, which should get redirected to Logcat on Android

How to update activity UI when app is in background/closed

I have a service which controls my mediaplayer object and when i close my app, a notification is still shown to control playback.
Now when a song is done playing i want update the UI in my activity and i did this with a broadcastreceiver, but this only works when my app is visible and not in the background/closed. (unregistered broadcastreceiver in onPause)
But how do i keep listening for these events when my application is not visible and when the user opens my application again it has the updated UI (new song).
Service
#Override
public void onCompletion(MediaPlayer mp) {
Log.d(TAG, "OnCompletion called!");
Intent broadCastReceiverIntentUpdateSong = new Intent(Constants.ACTIONS.BROADCAST_UPDATE_SONG);
sendBroadcast(broadCastReceiverIntentUpdateSong);
}
When your app starts, it should ask the Service for the current state of the player and show that.
While the app is running and in the foreground, it can listen for the broadcast events and update the UI (or its own internal state) accordingly.
When your app goes to the background, it doesn't need to do anything. When it comes again to the foreground (in onResume()) it can again ask the Servicefor the current state of the player.
You can have the Activity bind to the Service and use AIDL to get the current state OR you can just call startService() with an Intent that contains an ACTION or an EXTRA that indicates that you want to know the current state, and the Service can ract to that by sending a broadcast Intent containing the current state, which your Activity can listen for.

Android Wear Watchface Engine Never Calls DataApi Update

I have code like this for a watchface in Android Studio. I'm putting a random integer in the datamap so that the receiving side on the phone app can detect it as having been updated. I set this code in onConnected with the intent that every time the watchface is installed or 'chosen' by the user again, it will update data on the watchface - the main app receives this 'installed' status and then sends back updated information to the watch.
public class MyWatchFace extends CanvasWatchFaceService {
///
private class Engine extends CanvasWatchFaceService.Engine implements
DataApi.DataListener,
GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener{
#Override
public void onConnected(#Nullable Bundle bundle) {
Wearable.DataApi.addListener(mGoogleApiClient, this);
PutDataMapRequest putDataMapReq = PutDataMapRequest.create("/installed");
putDataMapReq.getDataMap().putInt(INSTALLED, new Random().nextInt());
PutDataRequest putDataReq = putDataMapReq.asPutDataRequest();
putDataReq.setUrgent();
Wearable.DataApi.putDataItem(mGoogleApiClient, putDataReq)
.setResultCallback(new ResultCallback<DataApi.DataItemResult>() {
#Override
public void onResult(DataApi.DataItemResult dataItemResult) {
Log.d(TAG, "Sending Install Status was successful: " + dataItemResult.getStatus()
.isSuccess());
}
});
}
The problem is that this section of code
Wearable.DataApi.putDataItem(mGoogleApiClient, putDataReq)
.setResultCallback
never seems to be called when I debug it, while installing or choosing the watchface again. I have to go to the phone app and update information on there for the information to be sent back to the watch.
I originally put the callback in the onCreate method of the Engine, but that was never called either. This is also where I create and connect the mGoogleApiClient, which IS successfully called.
Is there a more appropriate method to put this installed update code in? Why is it never being called in these 2 methods?
Everything else about the watch works fine - it successfully retrieves data from the phone app when the phone app data changes. PS, I use the same mGoogleApiClient to retrieve this phone data to also send the install status, in case you think that might be a problem. Do I have to create two separate clients?

Android: Run an app when it's definitively closed

I noted that when I close my app definitively, the method runInBackGround of the class MultiplyTask stops working. It works when the activity is in the phase STOP or PAUSE, but when I close my app, the method finishes ( it's a loop created with a cycle while(true) {...} ).
How can for example Whatsapp send notifications though it's closed? I want to create a similar thing. Thanks!
When the app is closed, all code will stop running. If you are looking to execute while the app is open and continue executing code while the app is closed, you will want to look into using a Service.
Take a thorough look at the Service documentation and it will hopefully be what you are looking for.
Services are also killed when your app is closed, but using the START_STICKY return value you can make sure your service is restarted upon termination.
EDIT WITH MORE INFORMATION:
<service
android:name="MyService" />
Add the above to your AndroidManifest.xml
public class MyService extends Service {
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
// This is where you would place your code that you want in the background
// Putting your while loop here will make sure it runs when the app is closed
return Service.START_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
//TODO for communication return IBinder implementation
return null;
}
}
Create a new class with the above code.
Intent i= new Intent(context, MyService.class);
startService(i);
Call this code from your launcher Activity to start the service when the app is launched.
Hope this helps!
Asynctask is ideal for short operation which are needed to be performed in the background. Usually Asyntask is implemented as sub class of activity which is destroyed when app is close. Also It communicates with the UI thread at some points ... so It needs the activity to be in memory... For long running operation, Service is better. Some Apps notify user even when they are not running. In fact they have one or more services running in background. You can see those in your phone setting->apps menu.
Study this for more information about services.

Stop already started service on application startup

I have an network app which uses a service to connect to other peers. When you close the application using "Recent apps" it will just close the process and not the service which is actually not bad for I want to be in this way. But it makes a little trouble next time user opens the app. It crashes so user has to again close the up using "Recent Apps" and then try to use the app again. The problem is definitely the running service because if I stop the service before I run it next time. It works just fine !
Actually it is strange for me because I don't start another service at the startup. I start it when user taps on a button. Anyway If it is possible the best way is to being able to use the running service, else, I just want to stop the service on start of my application.
i am new to android and I'm stuck at this point :(
Thanks for help
A service skeleton:
public class MyService extends Service {
public static final String TAG = "MyServiceTag";
...
}
This is part of the starting activity:
processStartService(MyService.TAG);
private void processStartService(final String tag) {
Intent intent = new Intent(getApplicationContext(), MyService.class);
intent.addCategory(tag);
startService(intent);
}
This is part of the stopping activity:
processStopService(MyService.TAG);
private void processStopService(final String tag) {
Intent intent = new Intent(getApplicationContext(), MyService.class);
intent.addCategory(tag);
stopService(intent);
}
Use one static object which indicate whether service is running or not.
otherwise second option I found How to check if a service is running on Android?,
if(startService(someIntent) != null) {
Toast.makeText(getBaseContext(), 'Service is already running',Toast.LENGTH_SHORT).show();
}else {
Toast.makeText(getBaseContext(), 'There is no service running, starting service..', Toast.LENGTH_SHORT).show();
}

Categories

Resources