Send "share intent" (ACTION_SEND) from activity to service - android

The task is to process somehow "share" intent in already running service.
As far as ACTION_SEND is an activity action we have to pick up intent in activity and broadcast it to service.
The problem is that it's logically to implement all "share intent" processing in service and use activity only for broadcasting intent.
So the service have to receive the intent (which previously received and broadcasted by activity) so we can call getType() and get****Extra***() to it in order to know what was actually shared and process this data somehow.
The intent we received in activity has the action ACTION_SEND (or ACTION_SEND_MULTIPLE), right? So logically we can change action with calling setAction() to intent object and broadcast it to our service which is already listening to this particular action.
public class HandleShareIntentActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent intent = getIntent();
Intent broadcastIntent = new Intent(intent);
// If I initialize empty intent there is no problem,
// I'll receive it in service
// Intent broadcastIntent = new Intent();
broadcastIntent.setAction(Constants.ACTION_SHARE);
broadcastIntent.setFlags(0);
sendBroadcast(broadcastIntent);
finish();
}
// ...
}
But that is not working, I'm not receiving this intent in service.
If I don't copy intent I got and broadcast an empty one, I do receive it in my service.
What I'm doing wrong?

First, to start a service, call startService(), not sendBroadcast(). There is no reason to have the service respond to broadcasts, and you are adding security problems to your app by doing so.
Second, you have to call startService() on an Intent that will identify your service (e.g., new Intent(this, ThisIsTheService.class)). In your case, you are taking an Intent identifying an activity, using a copy constructor to make a copy of it, changing the action string, and then trying to use that.
And, since an Intent is Parcelable, you could just add it as an extra to a service-specific Intent:
startService(new Intent(this, ThisIsTheService.class).putExtra(EXTRA_SEND, getIntent()));
and your service can pick EXTRA_SEND out in onHandleIntent() (if it is an IntentService) or onStartCommand() (if it is not). This code snippet assumes that you define EXTRA_SEND to be some string somewhere.

Related

Android Best-Way to communicate with a Foreground Service

I am bit new to android. I would like to know how to communicate with a foreground started service.
So, I got a Foreground service with a notification.
This notification has a (X) button to stop the service.
The service got a Static broadcastreceiver.
public static class NotificationStopButtonHandler extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context,"Close Clicked",Toast.LENGTH_SHORT).show();
Log.i(LOG_TAG, "In Closed");
// imposible to do context.stopForground(true) or
// to call any other private coded by me
}
}
So my question is :
Is BroadcastReceiver is the best way ?
If it is : How I can communicate with the service to call stopForeground in the broadcastReceiver ?
Thanks in advance for your responses.
Same question like mien... But I would like to know which are the other solution than broadcastReceiver. thx
In your notification you will have a PendingIntent for the X button. I presume you have built that PendingIntent with
PendingIntent.getBroadcast(/* ... */);
What you can do instead is to create a PendingIntent for your service
Intent intent = /* intent for starting your service */;
intent.putExtra("STOP_FOREGROUND", true);
PendingIntent.getService(context, requestCode, intent, flags);
and in the intent you pass to the PendingIntent you would add an extra (STOP_FOREGROUND). When this intent is fired, your service will get called in onStartCommand(). Here you check the intent and if it contains your extra, you know you're expected to call stopForeground.
Instead of broadcasts, you can use PendingIntent with an Intent to the Service and tell the Service to shut down. You assign the PendingIntent to the close button action and/or to the notifications onDelete call when you build the notification.
Assuming that you're starting the Service with the notification, you can put commands in the Intent to tell the service to stop itself. Service#onStartCommand will be called on the service with the new Intent. The service checks for the shutdown call and calls stopSelf() when done.
Basically, the reason this works is because there can only be one Service started. Every subsequent attempt to start the service will send the intent to Service#onStartCommand, but it will not restart the Service. Thus, this is a way you can send commands to the service through means outside of binding. Plus it's way cleaner than using broadcasts.

Knowing about Sticky intent in Android

In android there are 3 kinds of Intents,
Intent,
Sticky Intent,
Pending intent.
so What is sticky intent?
Intent - is a message passing mechanism between components of Android, except for Content Provider. You can use Intent to start any
component.
Sticky Intent - Sticks with Android, for future broadcast listeners. For example if BATTERY_LOW event occurs then that Intent
will stick with Android so that any future requests for
BATTERY_LOW, will return the Intent.
Pending Intent - If you want some one to perform any Intent operation at future point of time on behalf of you, then we will use
Pending Intent.
An intent that is used with sticky broadcast, is called as sticky intent.
This intent will stick with android system for future broadcast receiver requests.
OR
sendStickyBroadcast() performs a sendBroadcast(Intent) known as sticky, i.e. the Intent you are sending stays around after the broadcast is complete, so that others can quickly retrieve that data through the return value of registerReceiver(BroadcastReceiver, IntentFilter). In all other ways, this behaves the same as sendBroadcast(Intent). One example of a sticky broadcast sent via the operating system is ACTION_BATTERY_CHANGED. When you call registerReceiver() for that action -- even with a null BroadcastReceiver -- you get the Intent that was last broadcast for that action. Hence, you can use this to find the state of the battery without necessarily registering for all future state changes in the battery.
Pending Intent: Pending Intent is actually an object which wraps an Intent to do some future work by another app.
It lets us pass a future Intent to another application and allows that application to execute that Intent as if it had the same permissions as our application, whether or not our application is still around when the Intent is eventually invoked.
A PendingIntent is generally used in cases were an AlarmManager needs to be executed or for Notifications. A PendingIntent provides a mean for applications to work, even after their process exits.
PendingIntent uses the following methods to handle the different types of intents:
PendingIntent.getActivity() : Retrieve a PendingIntent to start an Activity
PendingIntent.getBroadcast() : Retrieve a PendingIntent to perform a Broadcast
PendingIntent.getService() : Retrieve a PendingIntent to start a Service
Example :
Intent intent = new Intent(this, SomeActivity.class);
// Creating a pending intent and wrapping our intent
PendingIntent pendingIntent = PendingIntent.getActivity(this, 1, intent, PendingIntent.FLAG_UPDATE_CURRENT);
try {
// Perform the operation associated with our pendingIntent
pendingIntent.send();
} catch (PendingIntent.CanceledException e) {
e.printStackTrace();
}
Intent: Intent is basically a message passing mechanism between different components of Android, except for Content Provider. You can use intent to start any component in Android.
Sticky Intent: These are the Intents which sticks with Android for future broadcast listener.
Sticky Intent is also a type of Intent which allows communication between a function and a service sendStickyBroadcast(), performs a sendBroadcast(Intent) known as sticky, the Intent you are sending stays around after the broadcast is complete, so that others can quickly retrieve that data through the return value of registerReceiver(BroadcastReceiver, IntentFilter). In all other ways, this behaves the same as sendBroadcast(Intent).
One example of a sticky broadcast sent via the operating system is ACTION_BATTERY_CHANGED. When you call registerReceiver() for that action — even with a null BroadcastReceiver — you get the Intent that was last Broadcast for that action. Hence, you can use this to find the state of the battery without necessarily registering for all future state changes in the battery.
Intent : Intent is an asynchronous message which is use to communicate between the components in android , except Content Provider.
for example you can start activity by
startActivity(Intent intent);
Sticky Intent : sticky intents are associated with the android system for the future broadcast events.
Pending Intent : Those intent which you want to trigger at some time in future when you application is not alive.
An intent that is used with sticky broadcast, is called as sticky intent. This intent will stick with android system for future broadcast receiver requests.
Sticky Intent allows a communication between function and a service sendStickyBroadcast() performs a sendBroadcast(Intent) know as sticky, the Intent you are sending stays around after the broadcast is complete so that others can quickly retrieve that data through the return value of registerReceiver(BroadcastReceiver, IntentFilter). In all other ways, this works the same as sendBroadcast(Intent).

How to send message/data from broadcast receiver (process1) to Service thread (process2) in android?

I am developing an android application. This application architecture is divided into 5 modules with 2 modules having multiple features. To develop this app, I am creating 2 process with multiple threads in them as required and 3 other threads. I have a some questions regarding this implementation:
Is this a good model? If not, why not? Right now I am considering only modularity.
I need to send a message from broadcast receiver in process1 to Service thread in process2, what is the best way to do it?
what is the best IPC mechanism in android? I tried to use this link, http://androidapps.org.ua/androidintro_ipc_intent.html which suggests startActivity and startActivityForResult, but these options are not available in broadcast receiver and service does not have startActivityForResult option.
Thank you.
Use Custom BroadcastReceiver
Write this in ActivityA.java
Intent intent = new Intent();
intent.putExtra("message","hi");
intent.setAction("com.android.activity.SEND_DATA");
sendBroadcast(intent);
Write this in ServiceA.java
private BroadcastReceiver mMessageReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// Extract data included in the Intent
String message = intent.getStringExtra("message");
Log.d("receiver", "Got message: " + message);
}
};
Now register Receiver
LocalBroadcastManager.getInstance(mContext).registerReceiver(mMessageReceiver,
new IntentFilter("com.android.activity.SEND_DATA"));
Just create an Intent in the BroadcastReceiver, add your data as extras, can call startService() with the Intent:
Intent intent = new Intent(context, MyService.class);
intent.putExtra("message", "whatever data you need to pass to the service");
context.startService(intent);
The method onStartCommand() will be called in your service with the passed Intent.
To answer your other question "what is the best IPC method", the answer (as always) is "that depends". Using Intents is the easiest method, as it is supported for all components out-of-the-box. If you need more complicated interaction between components you can look at using AIDL which will allow you to do remote method calls in a Service. If that still isn't enough, then just implement your own socket protocol between the 2 components.
First of all, trying to understand your terminologies. By process, I presume you mean activity and "service thread", I presume you mean a service.
If you want to send a message from onReceive() broadcast receiver, running in context of Activity 1, to a service which is already active, you can try one of the below:
1) Create a new intent (service class name as the class) and call startService() with the intent. Add the additional parameters you need as intent extras. It does not matter if your service is already active, the onStartCommand() is still called, you can have special parameters as intent extras to differentiate a onStartCommand() from onReceive.
2) If your scenario allows this, consider registering to same broadcast event in both your activity and service and act appropriately (then no need to pass messages)
3) Write another broadcast receiver in your service and call sendBroadcast() from the Activity's broadcast receiver

How to inform a service, that an activity has finished

I have a service, that starts an activity like this:
Intent i = new Intent();
i.setClass(this, MyActivity.class);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(i);
How to inform the service, that MyActivity has finished?
Any hints appreciated,
Marcus
in OnDestroy method of the activity, either you can invoke a method of the service, if you have service class object, if you don't have, Use Broadcast Receiver, to send some message, to Service, and in Service implement that Broadcast Receiver.

Android: How to tell when service is complete

I have an activity class that contains a button. When I click the button it starts a service that will populate my SQLite database in a separate thread. Once the service completes I would like a textview in my activity class to display a new value from the database.
I have everything set up correctly and my database is storing the correct info. The only thing I am still confused on is how do I tell my activity class that the service is complete?
You can send a broadcast when your service completes.
In your activity onResume
IntentFilter intentFilter = ; //Look up how to make an intent filter with an action as specified in the below service code
receiver =new BroadcastReceiver();
this.registerReceiver(receiver, intentFilter);
In your activity onPause
this.unregisterReceiver(receiver);
In your service.
Intent broadcastIntent = new Intent();
broadcastIntent.setAction("com.blablablaablla.ACTION_REFRESH");
this.sendBroadcast(broadcastIntent);
Create an Intent with your own action name "mike.intent.DB_POPULATE_DONE" or something... it's just a string you can examine in onNewIntent() if you choose to.
Send an Intent from the Service by calling Context.startActivity().
To receive the Intent, implement Activity.onNewIntent()

Categories

Resources