سؤال

So i'm using asmack library to listen for incoming xmpp packets. I've got the service implemented. It's started, bound, a method is run and then it's unbound. The service creates a PacketListener to get incoming messages, and displays a notification when a new message comes in. This all works while the app is the active activity, but doesn't work when it's fully closed (swiped away in the window list) and it's just the service running, the PacketListener doesn't fire. It fires as soon as the app is reopened though, firing off all notifications. I'm looking to get those notifications fired as they come in, instead of the service being suspended, if you will. The code for the service is here:

package com.jayseeofficial.xmpp.service;

import java.io.File;
import java.util.ArrayList;

import org.jivesoftware.smack.Connection;
import org.jivesoftware.smack.ConnectionConfiguration;
import org.jivesoftware.smack.ConnectionConfiguration.SecurityMode;
import org.jivesoftware.smack.PacketListener;
import org.jivesoftware.smack.RosterEntry;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.filter.PacketFilter;
import org.jivesoftware.smack.filter.PacketTypeFilter;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.packet.Packet;
import org.jivesoftware.smack.packet.Presence;
import org.jivesoftware.smack.packet.Presence.Type;

import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Binder;
import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
import android.support.v4.app.NotificationCompat;
import android.support.v4.app.TaskStackBuilder;
import android.util.Log;
import android.widget.Toast;

import com.jayseeofficial.xmpp.MainActivity;
import com.jayseeofficial.xmpp.Program;
import com.jayseeofficial.xmpp.R;
import com.jayseeofficial.xmpp.objects.Contact;
import com.jayseeofficial.xmpp.preferences.Preferences;

public class XMPPService extends Service {

    private Connection conn = null;
    private boolean loggedIn = false;

    private final XMPPBinder binder = new XMPPBinder();

    private Handler handler;

    @Override
    public IBinder onBind(Intent arg0) {
        handler = new Handler(getMainLooper());
        return binder;
    }

    public class XMPPBinder extends Binder {
        public XMPPService getService() {
            return XMPPService.this;
        }
    }

    public void logIn() {
        new LogInTask().execute();
    }

    public boolean isLoggedIn() {
        return loggedIn;
    }

    private ConnectionConfiguration getConnectionConfiguration() {
        ConnectionConfiguration config = new ConnectionConfiguration(
                Preferences.Account.getServer(), Preferences.Account.getServerPort());
        config.setSASLAuthenticationEnabled(true);
        config.setCompressionEnabled(true);
        config.setSecurityMode(SecurityMode.enabled);

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
            config.setTruststoreType("AndroidCAStore");
            config.setKeystoreType("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);
        }
        return config;
    }

    private void showNotification() {
        NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this)
                .setContentTitle("XMPP+").setContentText("running")
                .setSmallIcon(R.drawable.speech_bubble);

        Intent i = new Intent(this, MainActivity.class);

        TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
        stackBuilder.addParentStack(MainActivity.class);
        stackBuilder.addNextIntent(i);

        // Assign the intent
        mBuilder.setContentIntent(stackBuilder.getPendingIntent(9127,
                PendingIntent.FLAG_UPDATE_CURRENT));

        NotificationManager mgr = (NotificationManager) this
                .getSystemService(Context.NOTIFICATION_SERVICE);

        Notification n = mBuilder.build();

        n.flags |= Notification.FLAG_ONGOING_EVENT;

        mgr.notify(1,n);
    }

    private void hideNotification() {
        // TODO Implement hideNotification in XMPPService
    }

    private class LogInTask extends AsyncTask<Void, Void, Void> {

        @Override
        protected Void doInBackground(Void... params) {
            try {

                showNotification();

                // Set up and log in
                conn = new XMPPConnection(getConnectionConfiguration());
                conn.connect();
                conn.login(Preferences.Account.getUsername(), Preferences.Account.getPassword());

                // Set up to receive messages
                PacketFilter filter = new PacketTypeFilter(Message.class);
                conn.addPacketListener(new XMPPMessagePacketListener(), filter);
                conn.sendPacket(new Presence(Type.available));

                final ArrayList<Contact> allContacts = new ArrayList<Contact>();

                // Populate contact list
                for (RosterEntry re : conn.getRoster().getEntries()) {
                    Log.d("Roster entry: ", re.getUser() + ": " + re.getName());
                    Contact c = new Contact();
                    if (re.getName() == null) {
                        c.setName(re.getUser());
                    } else {
                        c.setName(re.getName());
                    }
                    c.setAddress(re.getUser());

                    allContacts.add(c);
                }

                handler.post(new Runnable() {
                    @Override
                    public void run() {
                        Program.contacts.addAll(allContacts);
                    }
                });

                loggedIn = true;
            } catch (XMPPException e) {
                e.printStackTrace();
            }
            return null;
        }

        @Override
        protected void onPostExecute(Void ignored) {
            if (loggedIn) {
                Toast.makeText(XMPPService.this, "Logged in successfully", Toast.LENGTH_LONG)
                        .show();
            } else {
                Toast.makeText(XMPPService.this, "Failed to log in", Toast.LENGTH_LONG).show();
            }
        }
    }

    private class XMPPMessagePacketListener implements PacketListener {
        @Override
        public void processPacket(Packet packet) {
            Message m = (Message) packet;
            if (m.getBody() != null) {
                com.jayseeofficial.xmpp.objects.Message message = new com.jayseeofficial.xmpp.objects.Message();
                message.setRecipient(Preferences.Account.getUsername() + "@"
                        + Preferences.Account.getServer());
                String fullSender = m.getFrom();
                String address = fullSender.substring(0, fullSender.indexOf('/'));
                message.setSender(address);
                message.setContents(m.getBody());
                Program.showMessageNotification(message, 9127);
            }
        }

    }
}

and the code for the starting/binding the service is here:

public static void init() {
        if (!initialized) {
            // Call other portions of init code first
            SmackAndroid.init(context);
            Preferences.init();

            // Set up our variables
            contacts = GlazedLists.threadSafeList(new BasicEventList<Contact>());

            // Start up the xmpp connection
            Intent ixmpp = new Intent(context, XMPPService.class);
            context.startService(ixmpp);
            context.bindService(ixmpp, xmppConnection, Context.BIND_AUTO_CREATE);

            initialized = true;
        }
    }

So as I said, i want to receive notifications from the service running in the background when the foreground activity is closed. Is there any way of doing this? Maybe have it in it's own process? Something else?

EDIT: the ongoing notification sticks around and works when clicked, in case you're wondering

هل كانت مفيدة؟

المحلول

use startforeground method http://developer.android.com/reference/android/app/Service.html#startForeground%28int,%20android.app.Notification%29

in onCreate of service

public void onCreate() {

 startForeground (int id, Notification notification)
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top