com.socialdisasters.service.ChatService.java Source code

Java tutorial

Introduction

Here is the source code for com.socialdisasters.service.ChatService.java

Source

/*
 * ChatService.java
 * 
 * Copyright (C) 2011 IBR, TU Braunschweig
 *
 * Written-by: Johannes Morgenroth <morgenroth@ibr.cs.tu-bs.de>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */
package com.socialdisasters.service;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Date;
import java.util.Locale;
import java.util.StringTokenizer;

import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.database.Cursor;
import android.media.AudioManager;
import android.net.Uri;
import android.os.Binder;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Looper;
import android.os.ParcelFileDescriptor;
import android.os.PowerManager;
import android.preference.PreferenceManager;
import android.support.v4.app.NotificationCompat;
import android.support.v4.app.NotificationCompat.WearableExtender;
import android.support.v4.app.RemoteInput;
import android.support.v4.app.TaskStackBuilder;
import android.util.Log;
import de.tubs.ibr.dtn.api.Block;
import de.tubs.ibr.dtn.api.Bundle;
import de.tubs.ibr.dtn.api.Bundle.ProcFlags;
import de.tubs.ibr.dtn.api.BundleID;
import de.tubs.ibr.dtn.api.DTNClient;
import de.tubs.ibr.dtn.api.DTNClient.Session;
import de.tubs.ibr.dtn.api.DTNIntentService;
import de.tubs.ibr.dtn.api.DataHandler;
import de.tubs.ibr.dtn.api.GroupEndpoint;
import de.tubs.ibr.dtn.api.Registration;
import de.tubs.ibr.dtn.api.ServiceNotAvailableException;
import de.tubs.ibr.dtn.api.SessionDestroyedException;
import de.tubs.ibr.dtn.api.SingletonEndpoint;
import de.tubs.ibr.dtn.api.TransferMode;

public class ChatService extends DTNIntentService {

    public enum Debug {
        NOTIFICATION, BUDDY_ADD, SEND_PRESENCE, UNREGISTER
    }

    private static final String TAG = "ChatService";

    public static final String EXTRA_USER_ID = "com.socialdisasters.USER_ID";
    public static final String EXTRA_TEXT_BODY = "com.socialdisasters.TEXT_BODY";
    public static final String EXTRA_DISPLAY_NAME = "com.socialdisasters.DISPLAY_NAME";
    public static final String EXTRA_PRESENCE = "com.socialdisasters.EXTRA_PRESENCE";
    public static final String EXTRA_STATUS = "com.socialdisasters.EXTRA_STATUS";
    public static final String EXTRA_VOICE_REPLY = "extra_voice_reply";

    // mark a specific bundle as delivered
    public static final String MARK_DELIVERED_INTENT = "com.socialdisasters.MARK_DELIVERED";
    public static final String REPORT_DELIVERED_INTENT = "com.socialdisasters.REPORT_DELIVERED";

    public static final String ACTION_NEW_MESSAGE = "com.socialdisasters.ACTION_NEW_MESSAGE";
    public static final String ACTION_PRESENCE_ALARM = "com.socialdisasters.PRESENCE_ALARM";
    public static final String ACTION_SEND_MESSAGE = "com.socialdisasters.SEND_MESSAGE";
    public static final String ACTION_REFRESH_PRESENCE = "com.socialdisasters.REFRESH_PRESENCE";
    public static final String ACTION_USERINFO_UPDATED = "com.socialdisasters.USERINFO_UPDATED";

    private static final int MESSAGE_NOTIFICATION = 1;
    private static final int REFRESH_BUDDY_DATA = 2;

    public static final String ACTION_OPENCHAT = "com.socialdisasters.OPENCHAT";
    public static final GroupEndpoint PRESENCE_GROUP_EID = new GroupEndpoint("dtn://chat.dtn/presence");

    private boolean _unregister_on_destroy = false;

    private final static String FALLBACK_NICKNAME = "Nobody";

    // This is the object that receives interactions from clients.  See
    // RemoteService for a more complete example.
    private final IBinder mBinder = new LocalBinder();

    // DTN client to talk with the DTN service
    private DTNClient.Session _session = null;

    // handler for scheduled refreshes
    private UpdateHandler mUpdateHandler = null;
    private HandlerThread mUpdateThread = null;

    public ChatService() {
        super(TAG);
    }

    public final static class UpdateHandler extends Handler {

        public UpdateHandler(Looper looper) {
            super(looper);
        }

        @Override
        public void handleMessage(android.os.Message msg) {
            super.handleMessage(msg);
        }
    }

    private DataHandler _data_handler = new DataHandler() {
        ByteArrayOutputStream stream = null;
        Bundle current;
        Long flags = 0L;

        public void startBundle(Bundle bundle) {
            this.current = bundle;
            this.flags = 0L;

        }

        public void endBundle() {
            de.tubs.ibr.dtn.api.BundleID received = new de.tubs.ibr.dtn.api.BundleID(this.current);

            // run the queue and delivered process asynchronously
            Intent i = new Intent(ChatService.this, ChatService.class);
            i.setAction(MARK_DELIVERED_INTENT);
            i.putExtra("bundleid", received);
            startService(i);

            this.current = null;
        }

        public TransferMode startBlock(Block block) {
            // ignore messages with a size larger than 8k
            if ((block.length > 8196) || (block.type != 1))
                return TransferMode.NULL;

            // create a new bytearray output stream
            stream = new ByteArrayOutputStream();

            return TransferMode.SIMPLE;
        }

        public void endBlock() {
            if (stream != null) {
                String msg = new String(stream.toByteArray());
                stream = null;

                if (current.getDestination().equals(PRESENCE_GROUP_EID)) {
                    eventNewPresence(current.getSource(), current.getTimestamp().getDate(), msg, flags);
                } else {
                    eventNewMessage(current.getSource(), current.getTimestamp().getDate(), msg, flags);
                }
            }
        }

        public void payload(byte[] data) {
            if (stream == null)
                return;
            // write data to the stream
            try {
                stream.write(data);
            } catch (IOException e) {
                Log.e(TAG, "error on writing payload", e);
            }
        }

        public ParcelFileDescriptor fd() {
            return null;
        }

        public void progress(long current, long length) {
        }

        private void eventNewPresence(SingletonEndpoint source, Date created, String payload, Long flags) {
            Log.i(TAG, "Presence received from " + source);

            // buddy info
            String nickname = null;
            String presence = null;
            String status = null;
            String voiceeid = null;
            String language = null;
            String country = null;

            StringTokenizer tokenizer = new StringTokenizer(payload, "\n");
            while (tokenizer.hasMoreTokens()) {
                String data = tokenizer.nextToken();

                // search for the delimiter
                int delimiter = data.indexOf(':');

                // if the is no delimiter, ignore the line
                if (delimiter == -1)
                    return;

                // split the keyword and data pair
                String keyword = data.substring(0, delimiter);
                String value = data.substring(delimiter + 1, data.length()).trim();

                if (keyword.equalsIgnoreCase("Presence")) {
                    presence = value;
                } else if (keyword.equalsIgnoreCase("Nickname")) {
                    nickname = value;
                } else if (keyword.equalsIgnoreCase("Status")) {
                    status = value;
                } else if (keyword.equalsIgnoreCase("Voice")) {
                    voiceeid = value;
                } else if (keyword.equalsIgnoreCase("Language")) {
                    language = value;
                } else if (keyword.equalsIgnoreCase("Country")) {
                    country = value;
                }
            }

            if (nickname != null) {

                // set timer to update buddy status if presence is not 'unavailable'
                if (!"unavailable".equals(presence)) {
                    // obtain a new refresh message
                    android.os.Message msg = mUpdateHandler.obtainMessage(REFRESH_BUDDY_DATA, source.toString());

                    // schedule the update in 61 minutes
                    mUpdateHandler.sendMessageDelayed(msg, 61 * 60 * 1000);

                    Log.d(TAG, "scheduled update for " + source.toString());
                }
            }
        }

        private void eventNewMessage(SingletonEndpoint source, Date created, String payload, Long flags) {
            if (source == null) {
                Log.e(TAG, "message source is null!");
            }

            // create a status bar notification
            Log.i(TAG, "New message received!");
        }
    };

    /**
     * Class for clients to access.  Because we know this service always
     * runs in the same process as its clients, we don't need to deal with
     * IPC.
     */
    public class LocalBinder extends Binder {
        public ChatService getService() {
            return ChatService.this;
        }
    }

    @Override
    public IBinder onBind(Intent intent) {
        return mBinder;
    }

    @Override
    public void onCreate() {
        // call onCreate of the super-class
        super.onCreate();

        // create a new background looper
        mUpdateThread = new HandlerThread(TAG, android.os.Process.THREAD_PRIORITY_BACKGROUND);
        mUpdateThread.start();
        Looper looper = mUpdateThread.getLooper();
        mUpdateHandler = new UpdateHandler(looper);

        // create registration
        Registration registration = new Registration("chat");
        registration.add(PRESENCE_GROUP_EID);

        try {
            initialize(registration);
        } catch (ServiceNotAvailableException e) {
        } catch (SecurityException ex) {
        }

        // register to presence changes
        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
        prefs.registerOnSharedPreferenceChangeListener(mPrefListener);

    }

    private SharedPreferences.OnSharedPreferenceChangeListener mPrefListener = new SharedPreferences.OnSharedPreferenceChangeListener() {
        @Override
        public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
            if ("presencetag".equals(key)) {
                String announced = prefs.getString("announced-presence", "unavailable");
                String desired = prefs.getString(key, "unavailable");

            }
        }
    };

    @Override
    public void onDestroy() {
        // unregister preference listener
        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
        prefs.unregisterOnSharedPreferenceChangeListener(mPrefListener);

        try {
            // stop looper
            mUpdateThread.quit();
            mUpdateThread.join();
        } catch (InterruptedException e) {
            Log.e(TAG, "Wait for looper thread was interrupted.", e);
        }

        // destroy the session if the unregister option is enabled
        if (_unregister_on_destroy && _session != null)
            _session.destroy();

        super.onDestroy();

        Log.i(TAG, "service destroyed.");
    }

    @Override
    protected void onHandleIntent(Intent intent) {
        // stop processing if the session is not assigned
        if (_session == null)
            return;

        String action = intent.getAction();

        // create a task to process concurrently
        if (ACTION_PRESENCE_ALARM.equals(action)) {
        } else if (MARK_DELIVERED_INTENT.equals(action)) {

        } else if (ACTION_SEND_MESSAGE.equals(action)) {
            //Long buddyId = intent.getLongExtra(ChatService.EXTRA_USER_ID, -1);
            //String text = intent.getStringExtra(ChatService.EXTRA_TEXT_BODY);

            // abort if there is no buddyId
            //if (buddyId < 0) return;

            actionSendMessage("dtn://androd-7e424bc4.dtn", "HOLaa");
        } else if (ACTION_NEW_MESSAGE.equals(action)) {
            //aqui un nuevo mensaje!!!
            //showNotification(intent);
        }
    }

    private void actionSendMessage(String idUser, String text) {
        SingletonEndpoint endpoint = new SingletonEndpoint(idUser);
        try {
            _session.send(endpoint, 3600, text.getBytes());
            Log.e(TAG, "Session SEND");
        } catch (SessionDestroyedException e) {
            e.printStackTrace();
            Log.e(TAG, " Session destroyer al enviar");
        }
    }

    @Override
    protected void onSessionConnected(Session session) {
        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);

        /**
         * Upgrade from "checkBroadcastPresence" option
         */
        if (prefs.contains("checkBroadcastPresence")) {
            if (!prefs.getBoolean("checkBroadcastPresence", false)) {
                prefs.edit().putString("presencetag", "unavailable").remove("checkBroadcastPresence").commit();
            } else {
                prefs.edit().remove("checkBroadcastPresence").commit();
            }
        }

        /**
         * Activate presence by default
         */
        if (!prefs.contains("presencetag"))
            prefs.edit().putString("presencetag", "auto").commit();
        mPrefListener.onSharedPreferenceChanged(prefs, "presencetag");

        // register own data handler for incoming bundles
        session.setDataHandler(_data_handler);

        // store session locally
        _session = session;

        // signal updated user info
        Intent i = new Intent(ACTION_USERINFO_UPDATED);
        sendBroadcast(i);
    }

    @Override
    protected void onSessionDisconnected() {
        _session = null;
    }
}