Running tasks from broadcast receiver while app is closed [Android] - android

I have an app that downloads data and put it into an SQLite Database when a notification is issued. This works fine while the app is in use but I need it to work when the app is closed too.
I have set up a BroadcastReceiver within that is called when the app is closed but I'm not sure how to get it to continue with adding to the database.
Here is the code I am using:
AndroidManifest.xml
<manifest....
<application...
<receiver android:name=".broadcast.PacksReceiver" >
<intent-filter>
<action android:name="ADD_PACK" >
</action>
</intent-filter>
</receiver>
PacksReceiver
public class PacksReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Log.d("PacksReceiver", "onReceive");
String message = intent.getStringExtra("message");
PacksActivity pa = new PacksActivity();
pa.downloadPack(null, message);
}
}
PacksActivity
public void downloadPack(View v, String thisPackID){
Log.d("download", "pack");
//THIS LOG IS CALLED EVERYTIME
vRef = v;
if(vRef != null){
runOnUiThread(new Runnable() {
#Override
public void run() {
onScreenProgressBar = (ProgressBar) vRef.findViewById(R.id.onScreenProgress);
onScreenProgressCircle = (ProgressBar) vRef.findViewById(R.id.onScreenProgressCircle);
dlPercent = (TextView) vRef.findViewById(R.id.dlPercent);
onScreenProgressCircle.setVisibility(View.VISIBLE);
onScreenProgressBar.setVisibility(View.VISIBLE);
onScreenProgressCircle.setProgress(0);
}
});
}
if(thisPackID == null){
thisPackID = pack_id;
}
String url = MyApp.getAppContext().getString(R.string.serverURL) +
MyApp.getAppContext().getString(R.string.getAppendixA) + "/" + thisPackID;
Intent appA_Intent = new Intent(Intent.ACTION_SYNC, null, this, DownloadService.class);
appA_Intent.putExtra("url", url);
appA_Intent.putExtra("onCreate", "false");
appA_Intent.putExtra("receiver", downloadPackReceiver);
appA_Intent.putExtra("downloadType", "GET_APPENDIX_A");
appA_Intent.putExtra("requestId", 101);
MyApp.getAppContext().startService(appA_Intent);
}

start the Service from
onReceive()
method because you can get mutiple broadcast one after another.

Write the code to add data in your database in your PackReciever inside OnRecieve() Method because that is where you recieve push notifications.

Don't call activity inside the receiver. Instead, use IntentService to download all packs. IntentService automatically finishes once it completes its work.
Override its onHandleIntent() method and download packs and save to database there.

Related

Use Intent.ACTION_TIME_TICK

How do I use Intent.ACTION_TIME_TICK correctly?
I would like to create a receiver which checks the battery-level every minute.
I use a Broadcast-receiver class witch is first started from main-Activity.
Starting the broadcast receiver is not the problem. When the app is open everything works fine. However, if the app ends, I will no longer receive broadcast information.
Now to my problem: how can I continue to receive information after completing the app?
My Sourcecode.
Start the Broadcast:
public class Main extends AppCompatActivity {
[...]
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
String app = getResources().getString(R.string.app_name);
[...]
btnStart.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View v) {
registerReceiver(receiver, new IntentFilter(Intent.ACTION_TIME_TICK));
Log.d(app + ".Main", "register receiver with '" + Intent.ACTION_TIME_TICK + "'");
}
});
}
}
Receive information in Receiver.class:
public class Receiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
BatteryManager bm = (BatteryManager)context.getSystemService(context.BATTERY_SERVICE);
int akku = bm.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY);
Calendar calendar = Calendar.getInstance();
int minute = calendar.get(Calendar.MINUTE);
if(action.equals(Intent.ACTION_TIME_TICK))
{
Log.d(app + ".Receiver", "Receiver detected '" + action + "'");
if(minute%5 == 0) {
startNotification(akku);
}
}
}
}
Manifest:
<receiver android:name=".Receiver"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.ACTION_TIME_TICK"></action>
</intent-filter>
</receiver>
You need to registre the receiver in Service, than it will work on background.
I dont know it on 100%, but I think that TIME_TICK doesnt work if you define it in manifest, you must register it in class.
you need to register your broadcaster subclass either on subclassed applicant onCreate() {...} or in your activity..
You can use the service for running in the background even after your app is closed and will notify the required.

Send data to BroadcastReceiver that is broadcasted in DownloadManager? [duplicate]

I am trying to pass an object to a BroadcastReceiver which will do something when a download is finished. How do I access the Intent object in the BroadcastReceiver's onReceive method from my activity? Right now I have this in my activity:
DownloadManager manager = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE);
long id = manager.enqueue(request);
and I have this in my BroadcastReceiver that does stuff when the download is complete:
DownloadManager mgr = (DownloadManager)context.getSystemService(Context.DOWNLOAD_SERVICE);
It all works fine, my BroadcastReceiver does what I want when the download completes. But now I want to pass an object from my activity to the BroadcastReceiver. Usually, I would just create an Intent and add the object to the Intent. But, I haven't created an Intent in my code because the BroadcastReceiver responds to the download using the Context.DOWNLOAD_SERVICE.
In my BroadcastReceiver, I want to get data from the Intent object in the onReceive() method here:
#Override
public void onReceive(Context context, Intent intent)
{
intent.getParcelableExtra("object");
}
How do I pass data into this Intent object from my activity? How do I access it? I tried using getIntent().putExtra("object", object) but it seems to be a different Intent than the one used in the BroadcastReceiver's onReceive method because I get a nullPointerException
Edit: here is my relevant code in AndroidManifest.xml
<receiver
android:name="com.android.devon.appfrenzy.DownloadReceiver"
android:exported="true" >
<intent-filter>
<action android:name="android.intent.action.DOWNLOAD_COMPLETE" />
</intent-filter>
</receiver>
But now I want to pass an object from my activity to the BroadcastReceiver.
That's not possible. The BroadcastReceiver does not exist, except when receiving the broadcast. Your entire process is perhaps gone by the time the download is complete.
You are welcome to store something in a persistent location (SharedPreferences, database, file) and read that in from onReceive(). That's the only way to pass data to an object that does not exist in a process that may not yet exist.
Before download is executed, save the value in SharedPreference
editor.putInt(MainActivity.CERIS_LAST_DW_ID_KATALOG, m_intIdKatalog);
editor.commit();
Then in onReceive get the value from Shared Preference
#Override
public void onReceive(Context arg0, Intent arg1) {
// TODO Auto-generated method stub
SharedPreferences mCeris;
mCeris = arg0.getSharedPreferences(MainActivity.CERIS_PREFERENCES,
Context.MODE_PRIVATE);
int m_intIdKatalog = mCeris.getInt(MainActivity.CERIS_LAST_DW_ID_KATALOG, 0);
}
I was struggling with this because using local storage doesn't work if you're trying to keep track of multiple queued downloads. Luckily the brainiancs at Google pass the Download ID through as an extra, so you can use:
long downloadId = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, 0)
Then use
public class DownloadReceiver extends BroadcastReceiver
{
#Override
public void onReceive(final Context context, final Intent intent)
{
long downloadId = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, 0)
DownloadManager manager = (DownloadManager) context.getSystemService(DOWNLOAD_SERVICE);
DownloadManager.Query query = new DownloadManager.Query();
query.setFilterById(downloadId);
Cursor cursor = manager.query(query);
if (cursor.moveToFirst()) {
int status = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS));
int reason = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_REASON));
}
cursor.close();
}
}
while calling send broadcast send data as
Intent i = new Intent();
i.putExtra("string_example", "here is a broadcasted string");
i.putExtra("int_example", 100);
sendBroadcast(i);
and in side onReceive() get data from Intent as
#Override
public void onReceive(Context context, Intent intent) {
Log.d(getString(R.string.app_name), "broadcast string: " + intent.getStringExtra("string_example"));
Log.d(getString(R.string.app_name), "extra!: " + intent.getIntExtra("int_example",0));
}
Modify as ur need...

how to detect and notify user of message from server?

app sent transaction to the server, user closes app, now a message needs to be
sent back to the phone from the server 10+ minutes later. The phone may be asleep, or the user might be checking his email. The question which I have is:
how can the phone be notified that a message has been received from server ?
how to display that message ?
A possible solution would be Google cloud messaging, but I still am not able to answer these 2 questions
1) You have to use SERVICE for that.
2) And to show that message.
Do like this.
The variable and method are members of Service class:
public final static String ACTION = "com.apps.example.MainActivity";
private void messageFromServer()//this method sends broadcast messages
{
Intent intent = new Intent(MOVEMENT_UPDATE);
String messageFromServer=serverMessage //here you will put server message
intent.putExtra("MessageFromServer", messageFromServer);
sendBroadcast(intent);
}
And this are the methods from Main activity:
You have to register receiver in the onResume method:
#Override
public void onResume()
{
IntentFilter intentFilter;
intentFilter= new IntentFilter(YourService.ACTION);
messageFromServer= new MessageFromServer();
registerReceiver(messageFromServer, intentFilter);
startYourService();
super.onResume();
}
private void startYourService()
{
startService(new Intent(this, YourService.class));
}
public class MessageFromServer extends BroadcastReceiver
{
#Override
public void onReceive(Context context, Intent intent)
{
// this method receives broadcast messages.
// Be sure to modify AndroidManifest.xml file in
// order to enable message receiving
String messageFromServer = intent.getStringExtra("MessageFromServer");
updateGUI();// here you can update the ui
}
}
and put service in you manifest file.
<service android:name="com.apps.service.YourService" ></service>

passing a variable from a service to a broadcast receiver

Hello guys i am trying to send two variables from an android service to a broadcast receiver, and i need help here..
i am setting up two var's in the oncreate method of the service class here..
#Override
public void onCreate() {
super.onCreate();
Intent eSendIntent = new Intent(getApplicationContext(), OutgoingCallReceiver.class);
eSendIntent.putStringArrayListExtra("BlockArray", contactsListB);
eSendIntent.putExtra("BlockBool", checkB);
getApplicationContext().sendOrderedBroadcast(eSendIntent, null);//Call receiver
}
and in my receiver class...
onReceive(Context context, Intent intent){
Bundle bundle = intent.getExtras();
if(bundle == null)
return;
boolean cb = bundle.getBooleanExtra("BlockBool", true);
ArrayList<String> ab = bundle.getStringArrayListExtra("BlockArray");
//disconnecting
try{
if(cb==false){
for(int ij = 0; ij < ab.size(); ij++){
if(ab.get(ij).contains(phonenumber)){
tempBoolean = true;
//Log.e("OutgoingCallReceiver", SmsBlockerService.contactsListB.get(ij));
}
}//for loop
if(tempBoolean==true){
setResultData(null);
Toast.makeText(context, phonenumber + " is Blocked", Toast.LENGTH_SHORT).show();
}
}else{
setResultData(null);
Toast.makeText(context, "All Out-Going Calls are Blocked", Toast.LENGTH_SHORT).show();
}//end of main if
} catch(Exception e){
Toast.makeText(context, "Detect Calls sample application Failed: ", Toast.LENGTH_LONG).show();
}
}
logcat:
E/BroadcastReceiver(1459): BroadcastReceiver trying to return result during a non-ordered broadcast
set this in your broadcast intent
i.setAction("MYACTION");
than set this in your manifest
<receiver android:name=".BroadcastClass" >
<intent-filter>
<action android:name="MYACTION" />
</intent-filter>
</receiver>
may be this should helpful
Assuming that you registered the receiver.Now try to make a small change:
boolean cb = bundle.getBooleanExtra("BlockBool", true);
ArrayList<String> ab = bundle.getStringArrayListExtra("BlockArray");
Update:
In the on create... call the broadcast like...
sendOrderedBroadcast(eSendIntent);
You are facing that error because , setResultData() function works only with OrderedBroadcast.
From Android Documentation:
public final void setResultCode (int code)
Added in API level 1
Change the current result code of this broadcast; only works with broadcasts sent
through Context.sendOrderedBroadcast. Often uses the Activity RESULT_CANCELED and
RESULT_OK constants, though the actual meaning of this value is ultimately up to the
broadcaster.
This method does not work with non-ordered broadcasts such as those sent with
Context.sendBroadcast.
for broadcast receiver to work the activity/screen in which it is written should be up & running. so that receiver can receives the passed intent & it's value.

'Share via' application that runs without a View

I want to write an app that sits in the 'Share via' menu (for quickly emailing myself links to things I find on the web or look at in RSS readers) For this I'm declaring my app with an intent.action.SEND intent-filter:
<activity
android:name="uk.co.baroquedub.checkit.MainActivity"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="text/plain" />
</intent-filter>
</activity>
Here's a skeleton of the MainActivity package
package uk.co.baroquedub.testcheck;
import android.app.Activity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.widget.Toast;
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// real code here grabs URL from intent then emails it as an asyncTask:
doSendTask task = new doSendTask();
task.execute(new String[] { "urlString" });
}
protected void showDialog (String response){
Toast.makeText(this, response, Toast.LENGTH_SHORT).show();
finish();
}
private class doSendTask extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... urls) {
String response = "";
// Real code here sends the email
// Simulate waiting for the email to be sent:
try {
Thread.sleep(5000);
response = "Waited";
}
catch (InterruptedException ex) { }
return response;
}
#Override
protected void onPostExecute(String result) {
showDialog(result);
}
}
}
The problem is that my app is opening on top of the browser (a white screen appears with a title bar showing the name of the app) - which is stopping the browser from being accessible until the 'wait' is finished (hence defeating the purpose of wrapping my sendEmail functionality within an asyncTask).
See: screencast for demo of problem
See: related question with full code
Can anyone tell me how I can have my app start (from the 'Share via' menu) and execute my code but without actually having a 'View' (if that's the right terminology for the blank screen and title bar)?
start an activity without any UI
start a service to do your background service in OnCreate
finish the activity as soon as you start service
let the service post notification or Toast about completion.
If you do want to show a dialog, you could start a separate activity with just the dialog from service, but it is usually intrusive to show dialog.
Thanks to Nandeesh for putting me on the right path. For those wanting to know exactly how to do it, here's the full solution:
1: start an activity without any UI
to do this I used the following Theme in the AndroidManifest:
android:theme="#android:style/Theme.NoDisplay"
which makes the initial application not just transparent but completely without a UI
2: start a service to do your background service in OnCreate
Here I still had to 'grab' the URL from the Share intent and pass it as an Extra to the service:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// get url
Intent intent = getIntent();
intent.setFlags( Intent.FLAG_ACTIVITY_CLEAR_TOP );
String action = intent.getAction();
// if this is from the share menu
if (Intent.ACTION_SEND.equals(action)) {
title = intent.getStringExtra(Intent.EXTRA_SUBJECT);
url = intent.getStringExtra(Intent.EXTRA_TEXT);
// Flipboard fix (remove title in URL)
url = url.replace(title, "");
if (url != null){
url = title+"\n"+url;
} else {
url = "error getting URL";
}
// prepare service
Intent emailSendIntent = new Intent(getApplicationContext(), EmailSendService.class);
emailSendIntent.putExtra("extraData", url);
startService(emailSendIntent);
finish();
}
}
3: finish the activity as soon as you start service
- see above
Note that in the service the Extras are passed to the OnStart method (not the On Create method as might be expected) See:
link
4: let the service post notification or Toast about completion.
I couldn't get the Service to open a Dialog notification(as per my original app), this kept on crashing the app/service but Toast works great - and as Nandeesh suggests, it's probably less intrusive.
Here's the service package:
public class EmailSendService extends Service {
String url;
String message;
#Override
public IBinder onBind(Intent arg0) {
return null;
}
#Override
public void onCreate() {
super.onCreate();
}
#Override
public void onDestroy() {
super.onDestroy();
}
#Override
public void onStart(Intent intent, int startId) {
super.onStart(intent, startId);
url = intent.getExtras().getString("extraData");
String senderPassword = getResources().getString(R.string.senderPassword);
String senderEmail = getResources().getString(R.string.senderEmail);
String recipientEmail = getResources().getString(R.string.recipientEmail);
String subjectText = getResources().getString(R.string.subjectText);
GMailSender sender = new GMailSender(senderEmail, senderPassword);
try {
sender.sendMail(subjectText,
url,
senderEmail,
recipientEmail);
message = "Email sent";
} catch (Exception e) {
message = "Error sending email";
}
Toast.makeText(this, message, Toast.LENGTH_LONG).show();
}
}
NB. remember to declare the service in the manifest (inside the application tag):
<service
android:name=".EmailSendService"
android:label="CheckIt EmailSendService" >
</service>

Categories

Resources