In my app i am using XMPP for chatting, in this i have to create a service to download all the contacts from the XMPP sever to my DataBase. i am doing like below code now, it takes much time to get all contacts, i don't have interest user let to wait to complete download all contacts.
Due to this reason i want to use a service to do this job in background and then store them in DB, i will use provider to update the contacts if database have a new contact.
I know how to create a service but here i am unable to pass parameter like Roster and XMPP connection to service, these parameters are required to download contacts from XMPP server.
please anybody guide me how to solve this problem.
this is the code i am using now.
public class GmailXmppClient {
public GmailXmppClient(ChatAccountsFragment _fragment, Context _context) {
this.fragment = _fragment;
this.context = _context;
ConnectionConfiguration config = new ConnectionConfiguration(server_host, SERVER_PORT, SERVICE_NAME);
m_connection = new XMPPConnection(config);
try {
m_connection.connect();
} catch (XMPPException e) {
e.printStackTrace();
}
}
public Roster getRoster() {
Log.i(TAG, " getRoster ");
return m_connection.getRoster();
}
public boolean Login(String uname, String pass ) throws XMPPException {
m_connection.login(uname, pass);
this.fragment.Gtalk_logInComplete(uname, m_connection);
this.setPacketFilters();
Presence presence = new Presence(Presence.Type.available);
Log.i("ID", "" + presence);
m_connection.sendPacket(presence);
return true;
}
public void disconnect() {
m_connection.disconnect();
}
}
From the above code after this code
this.fragment.Gtalk_logInComplete(uname, m_connection);
this code will run to get contacts from xmpp server
private void getConts() {
Roster roster = colors_xmpp_client.getRoster();
String file_name;
for (RosterEntry entry : roster.getEntries()) {
if (entry.getType() == ItemType.to || entry.getType() == ItemType.both) {
boolean yes = Contact_data_source.checkUsername(entry.getUser());
Log.i(TAG, "Con=" + yes);
if (!yes) {
String na = entry.getUser();
String[] me = na.split("#");
Bitmap buddy_img = buddyImage(entry, _connection);
if (buddy_img != null)
file_name = Store(buddy_img);
else
file_name = "";
if (entry.getName() == null)
Contact_data_source.createContact( entry.getUser(), entry.getUser(), Uname, file_name, UsedStrings.SipAccount, me[0] );
else
Contact_data_source.createContact( entry.getName(), entry.getUser(), Uname, file_name, UsedStrings.SipAccount, me[0] );
} else {
Log.i(TAG, "Con=exist");
}
}
}
return null;
}
You can use the following flow:
1) start Activity, bind RosterService
2) register ContentObserver with desired context (application context, or activity)
context.getContentResolver().registerContentObserver(uriRosterChanged, true, contentObserver);
3) send this context and contentObserver to RosterService
4) in service: get contact and store it into db and !!! >>
5) in service: context.getContentResolver().notifyChange(uriRosterChanged, contentObserver)
6) repeat i.4 for the next contact
i.5 -> will fire contentObserver.onChange method, so here you may refresh your contacts list
How 2 send parameters to service 2 ways described with extras and direct method call (setRosterNConnection()):
Activity code:
...
RosterService mService;
#Override public void onCreate(Bundle savedInstanceState) {
...
Intent intent = new Intent(this, RosterService.class);
intent.putExtra("Key", "Value");
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
...
}
...
Roster mRoster ;
XMPPConnection mConnection;
...
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className,
IBinder service) {
LocalBinder binder = (LocalBinder) service;
mService = binder.getService();
mService.setRosterNConnection(mRoster, mConnection);
mService.doJob();
}
public void onServiceDisconnected(ComponentName arg0) {
mService = null;
}
};
...
RosterService code:
// some class LocalBinder extends Binder{...} if some needs
private LocalBinder mBinder = new LocalBinder(); // class LocalBinder extends Binder{...}
...
#Override
public IBinder onBind(Intent intent) {
Bundle extras = intent.getExtras();
if(extras == null)
Log.d("RosterService","extras is empty");
else
{
Log.d("RosterService","extras not empty");
String key = (String) extras.get("Key");
...
}
return mBinder;
}
...
public void setRosterNConnection (Roster roster , XMPPConnection connection){
...
}
...
public void doJob(){
// get and save contacts
...
}
Maybe you can do it in a AsyncTask.
AsyncTask just will do the work on another thread, just if user close your activity the asyncTask will be stopped.
Related
I am trying to create a basic chat app using asmack and Openfire.
I have created a bound service for the XMPPConnection and each Activity binds to it.
Whenever I try to bind to a Service there is a very long delay. I know that the bindService is asynchronous but I want to be certain that my implementation of the Service is correct before I begin looking elsewere for problems.
I bind my Service in the onCreate method and try to access the connection in the onStart.
I am still new to this but I suspect that I have done something wrong thread-wise. The way my app runs now, the mBound variable returns true only if I try to access it from an OnClickListener. What is it that happens in the Listener that makes such a big difference? I tried to find the code for the OnClick method but I couldn't find it.
My XMPPConnectionService is this:
package com.example.smack_text;
import java.io.File;
import org.jivesoftware.smack.ConnectionConfiguration;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.XMPPException;
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.Build;
import android.os.IBinder;
import android.util.Log;
import android.widget.Toast;
public class XMPPService extends Service{
XMPPConnection connection;
// private final IBinder mBinder = new LocalBinder();
#Override
public void onCreate(){
super.onCreate();
Log.d("service","created");
}
/**
* Class used for the client Binder. Because we know this service always
* runs in the same process as its clients, we don't need to deal with IPC.
*/
#Override
public IBinder onBind(Intent intent) {
Log.d("sevice","bound");
LocalBinder mBinder = new LocalBinder (this);
return mBinder;
}
public class LocalBinder extends Binder {
XMPPService service;
public LocalBinder (XMPPService service)
{
this.service = service;
}
public XMPPService getService (){
return service;
}
// XMPPService getService() {
// return XMPPService.this;
// }
}
public void connect(final String user, final String pass) {
Log.d("Xmpp Alex","in service");
ConnectionConfiguration config = new ConnectionConfiguration("10.0.2.2",5222);
// KEYSTORE SETTINGS
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
config.setTruststoreType("AndroidCAStore");
config.setTruststorePassword(null);
config.setTruststorePath(null);
}
else {
config.setTruststoreType("BKS");
String path = System.getProperty("javax.net.ssl.trustStore");
if (path == null)
path = System.getProperty("java.home") + File.separator + "etc"
+ File.separator + "security" + File.separator
+ "cacerts.bks";
config.setTruststorePath(path);
}
// Create XMPP Connection
connection = new XMPPConnection(config);
new Thread(new Runnable() {
#Override
public void run() {
try {
connection.connect();
connection.login(user, pass);
if(connection.isConnected()){
Log.d("Alex", "connected biatch!");
}
else{
Log.d("Alex","not connected");
}
} catch (XMPPException e) {
e.printStackTrace();
}
}
}).start();
}
public void disconnect(){
if(connection.isConnected()){
connection.disconnect();
}
else{
Toast.makeText(getApplicationContext(), "not connected", Toast.LENGTH_LONG).show();
}
}
}
I implement an Android Chat with Asmack.
I have created a Service.
The service has a global variable with the XmppConnection.
At the begining i use the thread for connect and login.
then I set VCard for logged user, set rosterListener
finally set connection.addPacketListener
I update the activities with a BroadcastReceiver activity side and
#Override
public IBinder onBind(Intent arg0) {
return mBinderXmpp;
}
public class BinderServiceXmpp extends Binder {
ServiceXmpp getService() {
return ServiceXmpp.this;
}
}
private Runnable sendUpdatesToUI = new Runnable() {
public void run() {
DisplayInfo();
handler.postDelayed(this, 2000); // 2 segundos
}
};
private void DisplayInfo() {
isRunning = true; // flag to know if service is running
Intent tempIntent;
tempIntent = new Intent(BROADCAST_ACTION);
tempIntent.putExtra("UPDATE_OPTION", UPDATE_ACTION);
sendBroadcast(tempIntent);
}
Your implementation works, you still need to implement the handler for the actions like CONNECT and DISCONNECT from your clients bound (LoginActivity for instance).
Example:
class IncomingHandler extends Handler { // Handler of incoming messages from clients bound.
#Override
public void handleMessage(android.os.Message msg) {
switch (msg.what) {
case MSG_CONNECT_XMPP:
new AsyncTask<Void, Void, Boolean>(){
#Override
protected Boolean doInBackground(Void... params) {
// Do connection
}
#Override
protected void onPostExecute(Boolean aBoolean) {
// Notify the connection status
}
}.execute();
break;
case MSG_DICCONNECT_XMPP:
new AsyncTask<Void, Void, Boolean>(){
#Override
protected Boolean doInBackground(Void... params) {
// Do disconnection
}
#Override
protected void onPostExecute(Boolean aBoolean) {
// Notify the connection status
}
}.execute();
break;
default:
super.handleMessage(msg);
}
}
}
But, this approach of creating an AsyncTask anytime the Service needs to run a network action will reach its limit for the sendBroadcast in a BroadcastReceiver.
If you have BroadcastReceiver that needs to start or stop the connection by sending a message to the XMPPService, you have something like this:
public class NetworkConnectivityReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
NetworkInfo network = cm.getActiveNetworkInfo();
network = intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO);
if (XmppService.isRunning() && network.isConnected()) {
context.sendBroadcast(new Intent(XmppService.ACTION_CONNECT));
} else if (XmppService.isRunning() && !network.isConnected()) {
context.sendBroadcast(new Intent(XmppService.ACTION_DISCONNECT));
}
}
}
Then, you will need to implement a Broadcast listener in the XmppService class.
But, you CANNOT run an AsyncTask in a Broadcast listener!
The remain options are described in my post here:
Android - Best option to implement Networking Class
My application has a database where queued items will be stored if it doesn't notice any connectivity to Wifi or mobile network, like 3G og 4G. My problem is:
I have a BroadcastReciever which is registrered this way:
#Override
public void onResume() {
super.onResume();
if(networkMonitor == null)
networkMonitor = new CaseQueueReceiver();
IntentFilter filter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
registerReceiver(networkMonitor, filter);
}
My BroadcastReciever is starting a Service to pick out items from this database and send them over either a webservice or mail. My BrodcastReciever is like this:
public class CaseQueueReceiver extends BroadcastReceiver {
boolean available;
QueueDB queueDB;
int count;
public CaseQueueReceiver() {
queueDB = new QueueDB(ContextHelper.context());
count = queueDB.countUnsentCases();
}
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
NetworkInfo info = intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO);
String typeName = info.getTypeName();
String subtypeName = info.getSubtypeName();
available = info.isAvailable();
Log.i("Network Monitor", "Network Type: " + typeName + ", subtype: " + subtypeName + ", available: " + available);
if (available && count > 0) {
Intent service = new Intent(context, SendQueuedCasesService.class);
context.startService(service);
}
}
}
}
As you can see if the internet connection is available and the database contains something, I will start a service to send these items in the database.
My Service looks like this:
public class SendQueuedCasesService extends Service {
boolean available;
DatabaseHandler db;
QueueDB queueDB;
HashMap<String, String> queueHashMap;
CreateTransaction transaction;
String pcn, file;
int sent;
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
super.onCreate();
db = new DatabaseHandler(ContextHelper.context());
queueDB = new QueueDB(ContextHelper.context());
queueHashMap = new HashMap<String, String>();
transaction = new CreateTransaction(ContextHelper.context());
queueDB = new QueueDB(this);
int count = queueDB.countUnsentCases();
Log.w("Unsent cases count: ", Integer.toString(count));
if (count > 0) {
queueHashMap = queueDB.getUnsetCases();
Iterator<Entry<String, String>> it = queueHashMap.entrySet().iterator();
while(it.hasNext()) {
Map.Entry pairs = it.next();
pcn = pairs.getKey().toString();
Log.w("PCN in Queued Cases: ", pcn);
file = pairs.getKey().toString();
Log.w("Nist File Path: ", file);
try
{
sent = transaction.createTransaction(pcn, file);
if(sent == -2)
{
queueDB.deleteUnSentCase(pcn);
db.updateDB(pcn, "");
}
else
break;
} catch(MailException e) {
Log.e("MailException: ", e.getMessage());
}
}
Intent i = new Intent(this, WorkflowChooser.getCurrentWorkflow());
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(i);
}
}
}
My problem is that when I start the application this will block the UI for a while and then show the UI. A other problems is that this service isn't triggered if I turn off and the on the WiFi again. Why is this happening?
My problem is that when I start the application this will block the UI for a while and then show the UI.
Service runs in UI thread. That's the problem.
You can try to use IntentService. It will handle all the threading for you automatically.
You should create an AsyncTask or a new thread which handles the Service.
I've looked at a number of other threads with similar titles, and none seem to cover my problem. So, here goes.
I'm using the Google market expansion files (apkx) library and sample code, with a few modifications. This code relies on receiving callbacks from a service which handles background downloading, licence checks etc.
I have a bug where the service doesn't get correctly attached, which results in a softlock. To make this more unhelpful, this bug never happens on some devices, but occurs about two thirds of the time on other devices. I believe it to be independent of Android version, certainly I have two devices running 2.3.4, one of which (a Nexus S) doesn't have the problem, the other (an HTC Evo 3D) does.
To attempt to connect to the service, bindService is called and returns true. OnBind then gets called as expected and returns a sensible value but (when the bug occurs) onServiceConnected doesn't happen (I've waited 20 minutes just in case).
Has anyone else seen anything like this? If not, any guesses for what I might have done to cause such behaviour? If no-one has any thoughts, I'll post some code tomorrow.
EDIT: Here's the relevant code. If I've missed anything, please ask.
Whilst adding this code, I found a minor bug. Fixing it caused the frequency of the problem I'm trying to solve to change from 2 times in 3 to about 1 time in 6 on the phone I'm testing it on; no idea about effects on other phones. This continues to suggest to me a race condition or similar, but I've no idea what with.
OurDownloaderActivity.java (copied and changed from Google sample code)
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
//Test the licence is up to date
//if (current stored licence has expired)
{
startLicenceCheck();
initializeDownloadUI();
return;
}
...
}
#Override
protected void onResume() {
if (null != mDownloaderClientStub) {
mDownloaderClientStub.connect(this);
}
super.onResume();
}
private void startLicenceCheck()
{
Intent launchIntent = OurDownloaderActivity.this
.getIntent();
Intent intentToLaunchThisActivityFromNotification = new Intent(OurDownloaderActivity
.this, OurDownloaderActivity.this.getClass());
intentToLaunchThisActivityFromNotification.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
Intent.FLAG_ACTIVITY_CLEAR_TOP);
intentToLaunchThisActivityFromNotification.setAction(launchIntent.getAction());
if (launchIntent.getCategories() != null) {
for (String category : launchIntent.getCategories()) {
intentToLaunchThisActivityFromNotification.addCategory(category);
}
}
// Build PendingIntent used to open this activity from Notification
PendingIntent pendingIntent = PendingIntent.getActivity(OurDownloaderActivity.this,
0, intentToLaunchThisActivityFromNotification,
PendingIntent.FLAG_UPDATE_CURRENT);
DownloaderService.startLicenceCheck(this, pendingIntent, OurDownloaderService.class);
}
initializeDownloadUI()
{
mDownloaderClientStub = DownloaderClientMarshaller.CreateStub
(this, OurDownloaderService.class);
//do a load of UI setup
...
}
//This should be called by the Stub's onServiceConnected method
/**
* Critical implementation detail. In onServiceConnected we create the
* remote service and marshaler. This is how we pass the client information
* back to the service so the client can be properly notified of changes. We
* must do this every time we reconnect to the service.
*/
#Override
public void onServiceConnected(Messenger m) {
mRemoteService = DownloaderServiceMarshaller.CreateProxy(m);
mRemoteService.onClientUpdated(mDownloaderClientStub.getMessenger());
}
DownloaderService.java (in Google market expansion library but somewhat edited )
//this is the onBind call that happens fine; the value it returns is definitely not null
#Override
public IBinder onBind(Intent paramIntent) {
return this.mServiceMessenger.getBinder();
}
final private IStub mServiceStub = DownloaderServiceMarshaller.CreateStub(this);
final private Messenger mServiceMessenger = mServiceStub.getMessenger();
//MY CODE, derived from Google's code
//I have seen the bug occur with a service started by Google's code too,
//but this code happens more often so is more repeatably related to the problem
public static void startLicenceCheck(Context context, PendingIntent pendingIntent, Class<?> serviceClass)
{
String packageName = serviceClass.getPackage().getName();
String className = serviceClass.getName();
Intent fileIntent = new Intent();
fileIntent.setClassName(packageName, className);
fileIntent.putExtra(EXTRA_LICENCE_EXPIRED, true);
fileIntent.putExtra(EXTRA_PENDING_INTENT, pendingIntent);
context.startService(fileIntent);
}
#Override
protected void onHandleIntent(Intent intent) {
setServiceRunning(true);
try {
final PendingIntent pendingIntent = (PendingIntent) intent
.getParcelableExtra(EXTRA_PENDING_INTENT);
if (null != pendingIntent)
{
mNotification.setClientIntent(pendingIntent);
mPendingIntent = pendingIntent;
} else if (null != mPendingIntent) {
mNotification.setClientIntent(mPendingIntent);
} else {
Log.e(LOG_TAG, "Downloader started in bad state without notification intent.");
return;
}
if(intent.getBooleanExtra(EXTRA_LICENCE_EXPIRED, false))
{
//we are here due to startLicenceCheck
updateExpiredLVL(this);
return;
}
...
}
}
//MY CODE, based on Google's, again
public void updateExpiredLVL(final Context context) {
Context c = context.getApplicationContext();
Handler h = new Handler(c.getMainLooper());
h.post(new LVLExpiredUpdateRunnable(c));
}
private class LVLExpiredUpdateRunnable implements Runnable
{
LVLExpiredUpdateRunnable(Context context) {
mContext = context;
}
final Context mContext;
#Override
public void run() {
setServiceRunning(true);
mNotification.onDownloadStateChanged(IDownloaderClient.STATE_LVL_UPDATING);
String deviceId = getDeviceId(mContext);
final APKExpansionPolicy aep = new APKExpansionPolicy(mContext,
new AESObfuscator(getSALT(), mContext.getPackageName(), deviceId));
// Construct the LicenseChecker with a Policy.
final LicenseChecker checker = new LicenseChecker(mContext, aep,
getPublicKey() // Your public licensing key.
);
checker.checkAccess(new LicenseCheckerCallback() {
...
});
}
}
DownloaderClientMarshaller.java (in Google market expansion library)
public static IStub CreateStub(IDownloaderClient itf, Class<?> downloaderService) {
return new Stub(itf, downloaderService);
}
and the Stub class from the same file:
private static class Stub implements IStub {
private IDownloaderClient mItf = null;
private Class<?> mDownloaderServiceClass;
private boolean mBound;
private Messenger mServiceMessenger;
private Context mContext;
/**
* Target we publish for clients to send messages to IncomingHandler.
*/
final Messenger mMessenger = new Messenger(new Handler() {
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_ONDOWNLOADPROGRESS:
Bundle bun = msg.getData();
if ( null != mContext ) {
bun.setClassLoader(mContext.getClassLoader());
DownloadProgressInfo dpi = (DownloadProgressInfo) msg.getData()
.getParcelable(PARAM_PROGRESS);
mItf.onDownloadProgress(dpi);
}
break;
case MSG_ONDOWNLOADSTATE_CHANGED:
mItf.onDownloadStateChanged(msg.getData().getInt(PARAM_NEW_STATE));
break;
case MSG_ONSERVICECONNECTED:
mItf.onServiceConnected(
(Messenger) msg.getData().getParcelable(PARAM_MESSENGER));
break;
}
}
});
public Stub(IDownloaderClient itf, Class<?> downloaderService) {
mItf = itf;
mDownloaderServiceClass = downloaderService;
}
/**
* Class for interacting with the main interface of the service.
*/
private ServiceConnection mConnection = new ServiceConnection() {
//this is the critical call that never happens
public void onServiceConnected(ComponentName className, IBinder service) {
// This is called when the connection with the service has been
// established, giving us the object we can use to
// interact with the service. We are communicating with the
// service using a Messenger, so here we get a client-side
// representation of that from the raw IBinder object.
mServiceMessenger = new Messenger(service);
mItf.onServiceConnected(
mServiceMessenger);
mBound = true;
}
public void onServiceDisconnected(ComponentName className) {
// This is called when the connection with the service has been
// unexpectedly disconnected -- that is, its process crashed.
mServiceMessenger = null;
mBound = false;
}
};
#Override
public void connect(Context c) {
mContext = c;
Intent bindIntent = new Intent(c, mDownloaderServiceClass);
bindIntent.putExtra(PARAM_MESSENGER, mMessenger);
if ( !c.bindService(bindIntent, mConnection, 0) ) {
if ( Constants.LOGVV ) {
Log.d(Constants.TAG, "Service Unbound");
}
}
}
#Override
public void disconnect(Context c) {
if (mBound) {
c.unbindService(mConnection);
mBound = false;
}
mContext = null;
}
#Override
public Messenger getMessenger() {
return mMessenger;
}
}
DownloaderServiceMarshaller.java (in Google market expansion library, unchanged)
private static class Proxy implements IDownloaderService {
private Messenger mMsg;
private void send(int method, Bundle params) {
Message m = Message.obtain(null, method);
m.setData(params);
try {
mMsg.send(m);
} catch (RemoteException e) {
e.printStackTrace();
}
}
public Proxy(Messenger msg) {
mMsg = msg;
}
#Override
public void requestAbortDownload() {
send(MSG_REQUEST_ABORT_DOWNLOAD, new Bundle());
}
#Override
public void requestPauseDownload() {
send(MSG_REQUEST_PAUSE_DOWNLOAD, new Bundle());
}
#Override
public void setDownloadFlags(int flags) {
Bundle params = new Bundle();
params.putInt(PARAMS_FLAGS, flags);
send(MSG_SET_DOWNLOAD_FLAGS, params);
}
#Override
public void requestContinueDownload() {
send(MSG_REQUEST_CONTINUE_DOWNLOAD, new Bundle());
}
#Override
public void requestDownloadStatus() {
send(MSG_REQUEST_DOWNLOAD_STATE, new Bundle());
}
#Override
public void onClientUpdated(Messenger clientMessenger) {
Bundle bundle = new Bundle(1);
bundle.putParcelable(PARAM_MESSENGER, clientMessenger);
send(MSG_REQUEST_CLIENT_UPDATE, bundle);
}
}
private static class Stub implements IStub {
private IDownloaderService mItf = null;
final Messenger mMessenger = new Messenger(new Handler() {
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_REQUEST_ABORT_DOWNLOAD:
mItf.requestAbortDownload();
break;
case MSG_REQUEST_CONTINUE_DOWNLOAD:
mItf.requestContinueDownload();
break;
case MSG_REQUEST_PAUSE_DOWNLOAD:
mItf.requestPauseDownload();
break;
case MSG_SET_DOWNLOAD_FLAGS:
mItf.setDownloadFlags(msg.getData().getInt(PARAMS_FLAGS));
break;
case MSG_REQUEST_DOWNLOAD_STATE:
mItf.requestDownloadStatus();
break;
case MSG_REQUEST_CLIENT_UPDATE:
mItf.onClientUpdated((Messenger) msg.getData().getParcelable(
PARAM_MESSENGER));
break;
}
}
});
public Stub(IDownloaderService itf) {
mItf = itf;
}
#Override
public Messenger getMessenger() {
return mMessenger;
}
#Override
public void connect(Context c) {
}
#Override
public void disconnect(Context c) {
}
}
/**
* Returns a proxy that will marshall calls to IDownloaderService methods
*
* #param ctx
* #return
*/
public static IDownloaderService CreateProxy(Messenger msg) {
return new Proxy(msg);
}
/**
* Returns a stub object that, when connected, will listen for marshalled
* IDownloaderService methods and translate them into calls to the supplied
* interface.
*
* #param itf An implementation of IDownloaderService that will be called
* when remote method calls are unmarshalled.
* #return
*/
public static IStub CreateStub(IDownloaderService itf) {
return new Stub(itf);
}
I have an application which listens incoming calls. The application has a database with a its own contact names and numbers.
When you get an incoming call, if the incoming number(say,1234) is not available in native contact database, the application checks it in it's database and finds the contact name from the database if number is available in it. (say, xyz)...
My aim is to refresh the incall screen with new contact name saying "xyz calling.." instead of "1234 calling.."..
Is it possible??..
Its not possible to refresh Incoming call screen but u can display desired name by fetching your own database... For that u need run ur own thread on incoming call screen, I used Timer and Timer Task to do so here is example
Your BroadcastReceiver should contain
ServiceReceiver extends BroadcastReceiver{
#Override
public void onReceive(final Context context, Intent intent) {
Bundle extras = intent.getExtras();
if (extras != null) {
String state = extras.getString(TelephonyManager.EXTRA_STATE);
incomingNumber = extras.getString("incoming_number");
if (state.equals(TelephonyManager.EXTRA_STATE_RINGING)) {
/********** Fetch name from your DB ************/
if (Name not present in your DB)
{
return;
}
if(present){
incomingCallTimer = new Timer();
ToastMessageHandler messageHandler = new ToastMessageHandler(context, contactName);
incomingCallTimer.schedule(new ToastTimer(messageHandler), 1000, 2000);
}
}
if (state.equals(TelephonyManager.EXTRA_STATE_IDLE)) {
// callActionHandler.removeCallbacks(runRingingActivity);
// setResultCode(Activity.RESULT_CANCELED);
try{
incomingCallTimer.cancel();
} catch (Exception e) {
}
}
}
class ToastTimer extends TimerTask {
ToastMessageHandler messageHandler;
public ToastTimer(ToastMessageHandler messageHandler) {
this.messageHandler = messageHandler;
}
#Override
public void run() {
Message message = Message.obtain(messageHandler);
messageHandler.sendMessage(message);
}
}
}
Toast Handler class
public class ToastMessageHandler extends Handler{
Context context;
String message;
public ToastMessageHandler(Context _context , String _message){
this.context = _context;
this.message = _message;
}
#Override
public void handleMessage(Message msg) {
Toast.makeText(msg);
}
}
I am trying to send a message to my main activity from an Async task embedded within a Service. Basically, the Async task has to block on input and it can't run in the main Activity thread (the blocking was removed from the example code below). When the data comes in though, I need to send it to the main activity. I am finding that the messages sent below never make it. If the answer is moving the bind within the Async task, how do you do that? Pointing to example code would be a big help if possible.
public class InputService2 extends Service {
int bufferSize = 1024;
Process process;
DataInputStream os;
TextView inputView;
byte[] buffer = new byte[bufferSize];
private MyAsyncTask inputTask = null;
public void onCreate(){
inputTask = new MyAsyncTask();
inputTask.execute((Void[])null);
}
private class MyAsyncTask extends AsyncTask<Void,Void,Void> {
int mValue = 0;
static final int MSG_SET_VALUE = 3;
protected void onProgressUpdate(Void progress){
}
protected void onPostExecute(Void result) {
}
protected Void doInBackground(Void... params) {
int i = 0;
try {
mValue = 0x23;
Message message = Message.obtain(null,MSG_SET_VALUE,mValue,0);
mMessenger.send(message);
}
catch (Exception e) {
}
}
}
class IncomingHandler extends Handler {
#Override
public void handleMessage(Message msg) {
}
}
final Messenger mMessenger = new Messenger(new IncomingHandler());
public IBinder onBind(Intent intent) {
return mMessenger.getBinder();
}
}
Below is inside the activity:
class IncomingHandler extends Handler {
#Override
public void handleMessage(Message msg) {
Context context = getApplicationContext();
int duration = Toast.LENGTH_LONG;
Toast toast = Toast.makeText(context, msg.arg1, duration);
toast.show();
}
}
boolean mBound;
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
// This is called when the connection with the service has been
// established, giving us the object we can use to
// interact with the service. We are communicating with the
// service using a Messenger, so here we get a client-side
// representation of that from the raw IBinder object.
mService = new Messenger(service);
mBound = true;
}
public void onServiceDisconnected(ComponentName className) {
// This is called when the connection with the service has been
// unexpectedly disconnected -- that is, its process crashed.
mService = null;
mBound = false;
}
};
protected void onStart() {
super.onStart();
// Bind to the service
bindService(new Intent(this, InputService2.class), mConnection,
Context.BIND_AUTO_CREATE);
}
It looks like you based your example on the javadoc reference at http://developer.android.com/reference/android/app/Service.html#RemoteMessengerServiceSample, however you left out much of the implementation detail that actually makes it work. You have to go back and implement the full functionality referenced in that example to use that particular pattern: pay careful attention to the REGISTER_CLIENT and UN_REGISTER_CLIENT implementation sections in the IncomingHandler class as these are the bits that actually ensure that the Message can be transferred from the Service to the Activity.