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>
Related
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.
I need a simple service (which will run in the background), when user copies anything from the browser or sms etc., there will be a toast showing that text.
example:
this service must be run on android 2.1 and later.
Today (from 10:35 AM to now[11:11 PM]) I've been searching the internet and tested several codes, but so far I have not come to a conclusion.
Some users in response to questions like this suggested that the use of the (my-clips) project. I get this, you can download this.
But this project is complex and I am confused.
can anyone show me a very simple example please?
thank you
Edit:
this is simple app run on background andoird OS. When the user does not open this app and copies any text from the browser or sms etc., this app will be active and show a toast like this: You copy this: ...
the way i did it was:
final ClipboardManager clipboard = (ClipboardManager) this.getSystemService(CLIPBOARD_SERVICE);
clipboard.addPrimaryClipChangedListener(new ClipboardManager.OnPrimaryClipChangedListener() {
public void onPrimaryClipChanged() {
String a = clipboard.getText().toString();
Toast.makeText(getBaseContext(), "Copy:\n" + a, Toast.LENGTH_LONG).show();
}
});
do it this way without service, add to manifest or anything, just open your app first then close it, and copy the text from anywhere to copy and show up in your app
for monitor Clipboard in android you need a service for monitoring clipboard and this service should be define in manifest.
your clip board service is here
https://github.com/twaddington/Android-Clipboard-Monitor/blob/master/src/com/example/clipboardmonitor/service/ClipboardMonitorService.java
and manifest define is in the below
<service
android:name=".service.ClipboardMonitorService"
android:label="Clipboard Monitor"
android:exported="false"/>
Here is what works for me.
First, the Broadcast:
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) {
ComponentName service = context.startService(
new Intent(context, ClipboardMonitor.class));
if (service == null) {
Log.e("TAG", "Can't start service");
}
} else {
Log.e("TAG", "Recieved unexpected intent " + intent.toString());
}
}
and then this is the service
private MonitorTask mTask = new MonitorTask();
private ClipboardManager mCM;
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
mCM = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE);
mTask.start();
}
#Override
public void onDestroy() {
mTask.cancel();
}
#Override
public void onStart(Intent intent, int startId) {
}
/**
* Monitor task: monitor new text clips in global system clipboard and
* new image clips in browser download directory
*/
private class MonitorTask extends Thread {
private volatile boolean mKeepRunning = false;
private String mOldClip = null;
public MonitorTask() {
super("ClipboardMonitor");
}
/** Cancel task */
public void cancel() {
mKeepRunning = false;
interrupt();
}
#Override
public void run() {
mKeepRunning = true;
while (true) {
doTask();
if (!mKeepRunning) {
break;
}
}
}
private void doTask() {
if (mCM.hasText()) {
String newClip = mCM.getText().toString();
if (!newClip.equals(mOldClip)) {
mOldClip = newClip;
// Toast.makeText(getApplicationContext(), "" + newClip.toString(), Toast.LENGTH_SHORT).show();
Log.i("TAG", "new text clip inserted: " + newClip.toString());
}
}
}
Also, the permissions:
<uses-permission android:name="android.permission.GET_CLIPS" />
<uses-permission android:name="android.permission.READ_CLIPS" />
<uses-permission android:name="android.permission.WRITE_CLIPS" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<service android:name=".ClipboardMonitor" />
<receiver android:name=".ClipboardMonitorStarter">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
What I'm trying to do
Hello Guys, I'm trying to create a SplashScreen which starts a Service over an Intent. After the Service is started to Activity(SplashScreen) should wait until it receive an Intent from my Service.
Question
What do I need to do, that my Activity waits until it received the Intent from my Service. It would be nice if you could provide me a good tutorial or some code-snippets.
Down here you find the Code of my SplashScreen.
Code
package de.stepforward;
import de.stepforward.service.VideoService;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
public class SplashActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.splash);
// Sagt dem Video-Service das er beginnen soll die
// Videos herunter zu laden
Intent LoadVideos = new Intent(this, VideoService.class);
LoadVideos.putExtra("VIDEO_SERVICE", "start");
startService(LoadVideos);
// In this thread I want that it waits for my Intent
// and than it goes to the next Activity
Thread splashThread = new Thread() {
#Override
public void run() {
try {
int waited = 0;
while (waited < 3000) {
sleep(100);
waited += 100;
}
}
catch (InterruptedException e) {
// do nothing
}
finally {
finish();
final Intent Showvideo = new Intent(SplashActivity.this,
ChannelTest.class);
startActivity(Showvideo);
}
}
};
splashThread.start();
}
}
Here is what your architecture should look like :
INTENT_CST
String START_INIT_ACTION = "your.package.name.START_INIT";
String INIT_ENDED_ACTION = "your.package.name.INIT_ENDED";
SplashActivity
In onCreate:
startService(new Intent(START_INIT_ACTION)
In onResume:
If you choose to send a broadcast in your service :
registerReceiver(new BroadcastReceiver(){
//implement onChange()},
new IntentFilter(INIT_ENDED_ACTION));
In onPause, unregister your receiver to free memory
LoadingService
Extend AsyncTask to do your background stuff. In onPostExecute, 2 options :
startActivity(new Intent(...)) // as your doing in your post
or
sendBroadcast(new Intent(INIT_ENDED_ACTION)); stopSelf();
Your manifest
Declare the service LoadingService with an IntentFilter with an <action name="your.package.name.START_INIT"/>
See this link it might be helpful for you. You can monitor your service state from your activity.
Restful API service
starting a service does not affect foreground screen .so launch splashscreen and start service , as you are doing right now . do operations in service, after that start new activity form service itself .
I am trying to implement a BroadcastReceiver but it is not working.
I want to use it to return progress from a class that implements network io, which is called from an AsyncTask inside my Activity.
Here is the code for my activity:
package com.ClinicalInterface;
public class TestActivity extends ListActivity {
static AsyncDataLoader mAsyncDataLoader;
static ProgressDialog dialog;
static ArrayList<String> list;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
dialog = new ProgressDialog(this);
dialog.setMessage("Loading...");
dialog.show();
mAsyncDataLoader = new AsyncDataLoader();
mAsyncDataLoader.execute();
}
public class AsyncDataLoader extends AsyncTask<Void, Integer, String> {
public class mTestReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent){
System.out.println( "I've received something!" );
publishProgress(2);
}
}
#Override
protected String doInBackground( Void ... params ) {
TestLoader tl = new TestLoader();
tl.setContext(getApplicationContext());
tl.setServeraddress("192.168.2.109");
list = tl.doLST(null);
return "COMPLETE!";
}
#Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
if (values[0] == 2) {
dialog.setMessage("Loading data ...");
}
}
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
dialog.dismiss();
ArrayAdapter<String> adapter = new ArrayAdapter<String>(TestActivity.this, R.layout.list_item, list);
TestActivity.this.setListAdapter(adapter);
}
}
}
This is supposed to display a list, then overlay this with a progress dialog while the data for the list is returned from a server. And this works OK.
I would like to update the text in the progress dialog as the network io is done.
This is the code that implements the network io:
package com.ClinicalInterface;
public class TestLoader {
private Context mContext;
public void setContext(Context context) {
mContext = context;
}
public ArrayList<String> doLST(String arg) {
// Send intent to AsyncTask
Intent intent = new Intent(mContext, mTestReceiver.class);
intent.setAction("PROGRESS");
mContext.sendBroadcast(intent);
System.out.println( "message sent" );
// Code that actually does network io removed for brevity
}
}
In the Android manifest file I've added the following:
<activity android:name="TestActivity" android:label="TestActivity">
<receiver android:name=".AsyncDataLoader.mTestReceiver">
<intent-filter>
<action android:name="android.intent.action.PROGRESS" />
</intent-filter>
</receiver>
</activity>
I get the log print "message sent"
But not the log print "I've received something"
I am an Android newbie so I assume I've not implemented something correctly.
Any ideas?
Original post updated with intent-filter and set of action when creating the intent. Still not working.
Your <receiver> tag needs to contain an <intent-filter> to tell Android which broadcast intents you actually want to receive.
EDIT:
An Intent is not much more than a container for a message; it's the function that you call to send the Intent that determines which fields you need to set.
From the docs for Intent:
[Intent] can be used with startActivity to launch an Activity, broadcastIntent to send it to any interested BroadcastReceiver components, and startService(Intent) or bindService(Intent, ServiceConnection, int) to communicate with a background Service.
Those functions are your options for sending Intents. startActivity and the startService/bindService functions use explicit Intents; sendBroadcast does not.
Notice that startActivity throws an exception if it can't find your Intent's target class, and startService will return null if it can't find your target class. sendBroadcast doesn't do anything like that because it doesn't even look at that field. sendBroadcast "Broadcasts the given intent to all interested BroadcastReceivers."
Since you are using Context.sendBroadcast() to send your intent, you should be setting an action on your Intent and your BroadcastReceiver should have an intent filter containing an entry for that action.
Ok
It seems like the answer is that its not possible to use the manifest to register the receiver.
If I change the code so that it uses registerReceiver then it works ok.
Code updated like this:
#Override
protected String doInBackground( Void ... params ) {
TestLoader tl = new TestLoader();
IntentFilter intentFilter = new IntentFilter("PROGRESS");
mReceiver mmReceiver = new mReceiver();
registerReceiver(mmReceiver, intentFilter);
tl.setContext(getApplicationContext());
tl.setServeraddress("192.168.2.109");
list = tl.doLST(null);
unregisterReceiver(mmReceiver);
return "COMPLETE!";
}
And remove anything to do with the receiver from the manifest.
Note: the code that sends the Broadcast is like this:
Intent intent = new Intent();
intent.setAction("PROGRESS");
mContext.sendBroadcast(intent);
I am starting a service using startService(Intent intent) method. When i call this function it reaches the onCreate of service but it is unable to call onStartCommand. Here is my code--
#Override
public void onReceive(Context context, Intent intent) {
// Send a text notification to the screen.
Log.e("mudit", "Action: " + intent.getAction());
try {
ConnectivityManager connManager = (ConnectivityManager) context
.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo info = connManager.getActiveNetworkInfo();
Log.e("mudit", "getType: " + info.getType());
Log.e("mudit", "isConnected: " + info.isConnected());
if (info.isConnected()) {
Intent newinIntent = new Intent(context, service.class);
context.startService(newinIntent);
}
} catch (Exception e) {
e.printStackTrace();
Intent newinIntent = new Intent(context, service.class);
context.stopService(newinIntent);
}
}
Service Code --
package com.android.service;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.widget.Toast;
public class service extends Service {
#Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return null;
}
#Override
public void onCreate() {
super.onCreate();
Toast.makeText(this, "Service created...", Toast.LENGTH_LONG).show();
}
#Override
public void onDestroy() {
super.onDestroy();
Toast.makeText(this, "Service destroyed ...", Toast.LENGTH_LONG).show();
}
public int onStartCommand(Intent intent, int flags, int startId) {
Toast.makeText(this, "onStartCommand...", Toast.LENGTH_LONG).show();
return 1;
}
}
Manifest.xml --
<receiver class=".AReceiver" android:name=".AReceiver">
<intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
</intent-filter>
</receiver>
<service class=".service" android:name=".service"
android:enabled="true" android:icon="#drawable/icon">
</service>
Unbound Service: it runs in the background indefinitely even started activity with service ends also.
Bound Service : it will run till life time of activity.
Activity can start service via startService() and it will stop via stopService().
If activity wants to interact with service, it can use bindService().
First onCreate() is called, after onStartCommand is called with the intent data provided by the activity.
Source
larsVogel solves this problem (and many others like it) in this excellent post.
this is how i adapted his code to create a connectivity receiver that monitors when the user connects to a WIFI network so as to batch upload usage data:
in the Manifest file, place a receiver and declare a service right before the end tag for your < / application >:
<receiver android:name=".ConnMonitor" android:enabled="true">
<intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
</intent-filter>
</receiver>
<service android:name=".BatchUploadGpsData" ></service>
</application>
create a broadcast receiver class in a separate file called ConnMonitor.java (please uncomment the Log calls to be able to properly monitor the flow)
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.util.Log;
public class ConnMonitor extends BroadcastReceiver {
private String TAG = "TGtracker";
#Override
public void onReceive(Context context, Intent intent) {
//String typeName = "";
String state = "";
int type = -1;
ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService( Context.CONNECTIVITY_SERVICE );
NetworkInfo test = (NetworkInfo) connectivityManager.getActiveNetworkInfo();
//Log.v(TAG,"there has been a CONNECTION CHANGE -> "+intent.getExtras().get(ConnectivityManager.EXTRA_NETWORK_INFO));
try {
//typeName = test.getTypeName().toString();
type = test.getType();
state = test.getState().toString();
//Log.i(TAG,"type -> '"+typeName +"' state -> '"+state+"'" );
} catch (Exception e) {
//typeName = "null";
type = -1;
state = "DISCONNECTED";
//Log.i(TAG,"type -> error1 "+e.getMessage()+ " cause = "+e.getCause() );
}
if ( (type == 1) && (state == "CONNECTED") ) {
//Log.i(TAG, "I am soooo friggin uploadin on this beautiful WIFI connection ");
Intent batchUploadDataService = new Intent(context, BatchUploadGpsData.class);
context.startService(batchUploadDataService);
} else {
//Log.e(TAG,"NO FOUND MATCH type -> '"+typeName +"' state -> '"+state+"'" );
}
}
}
and, finally, create a service BatchUploadGpsData.java like this:
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;
public class BatchUploadGpsData extends Service {
final String TAG = "TGtracker";
#Override
public void onCreate() {
Log.e(TAG, "here i am, rockin like a hurricane. onCreate service");
// this service tries to upload and terminates itself whether it is successful or not
// but it only effectively DOES anything while it is created
// (therefore, you can call 1 million times if uploading isnt done, nothing happens)
// if you comment this next line, you will be able to see that it executes onCreate only the first it is called
// the reason i do this is that the broadcast receiver is called at least twice every time you have a new change of connectivity state with successful connection to wifi
this.stopSelf();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
//Log.i(TAG, "Received start id " + startId + ": " + intent);
Log.e(TAG, "call me redundant BABY! onStartCommand service");
// this service is NOT supposed to execute anything when it is called
// because it may be called inumerous times in repetition
// all of its action is in the onCreate - so as to force it to happen ONLY once
return 1;
}
#Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
}
this is not pseudocode, this is actual code, tested and running on android 2.2 and up.
the way to test this service is to shut down and restart your WIFI services on your android (powering off the wifi router will also do the trick). BUT this code does not verify if you are effectively connected to the net. for that, i recomend that you make an httpclient request and check out the result of the call. beyond the scope of this discussion.
NOTE: since services run on the same thread as the UI, i highly recommend that you implement the uploading proper on a separate thread or asynctask, depending your specific needs. you can also run the whole service on a separate thread, but that is once again not the scope of this discussion, despite being standard practice in these cases.
First you should add #Override before onStartCommand(..) then make sure that the target for the Android project is higher than 2.0 .
I believe, that you cannot access any UI components like Dialog or even a Toast in a service.
try this.
public int onStartCommand(Intent intent, int flags, int startId) {
/* Toast.makeText(this, "onStartCommand...", Toast.LENGTH_LONG).show();
return 1; */
Log.i("YourService", "Yes this works.");
}
First of all name your class to something else is my recommendation to avoid confusion down the line. Second here is an example of my manifest call of a service I have that works. I use full path names when calling services and such since they are not in the same package as my application.
<service android:name="com.public.service.UploaderService" android:icon="#drawable/vgbio"></service>
Here is the gist of my service class,
package com.public.service;
....
public class UploaderService extends Service{
....
}
Third make sure you use #Override to the onStartCommand().