com.roamprocess1.roaming4world.service.SipNotifications.java Source code

Java tutorial

Introduction

Here is the source code for com.roamprocess1.roaming4world.service.SipNotifications.java

Source

/**
 * Copyright (C) 2010-2012 Regis Montoya (aka r3gis - www.r3gis.fr)
 * This file is part of CSipSimple.
 *
 *  CSipSimple 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.
 *  If you own a pjsip commercial license you can also redistribute it
 *  and/or modify it under the terms of the GNU Lesser General Public License
 *  as an android library.
 *
 *  CSipSimple 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 CSipSimple.  If not, see <http://www.gnu.org/licenses/>.
 */

package com.roamprocess1.roaming4world.service;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;

import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.graphics.Typeface;
import android.provider.CallLog;
import android.support.v4.app.NotificationCompat;
import android.support.v4.app.NotificationCompat.Builder;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.TextUtils;
import android.text.style.StyleSpan;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;

import com.roamprocess1.roaming4world.R;
import com.roamprocess1.roaming4world.api.SipCallSession;
import com.roamprocess1.roaming4world.api.SipManager;
import com.roamprocess1.roaming4world.api.SipMessage;
import com.roamprocess1.roaming4world.api.SipProfile;
import com.roamprocess1.roaming4world.api.SipProfileState;
import com.roamprocess1.roaming4world.api.SipUri;
import com.roamprocess1.roaming4world.models.CallerInfo;
import com.roamprocess1.roaming4world.ui.messages.MessageActivity;
import com.roamprocess1.roaming4world.utils.Compatibility;
import com.roamprocess1.roaming4world.utils.CustomDistribution;
import com.roamprocess1.roaming4world.utils.Log;
import com.roamprocess1.roaming4world.widgets.RegistrationNotification;

public class SipNotifications {

    private final NotificationManager notificationManager;
    private final Context context;
    private Builder inCallNotification;
    private Builder missedCallNotification;
    private Builder messageNotification;
    private Builder messageVoicemail;
    private boolean resolveContacts = true;

    public static final int REGISTER_NOTIF_ID = 1;
    public static final int CALL_NOTIF_ID = REGISTER_NOTIF_ID + 1;
    public static final int CALLLOG_NOTIF_ID = REGISTER_NOTIF_ID + 2;
    public static final int MESSAGE_NOTIF_ID = REGISTER_NOTIF_ID + 3;
    public static final int VOICEMAIL_NOTIF_ID = REGISTER_NOTIF_ID + 4;
    String imagefile = "R4WIMGTOCONTACTCHATSEND@@";

    private static boolean isInit = false;

    public SipNotifications(Context aContext) {
        context = aContext;
        notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);

        System.out.println("SipNotifications class");
        if (!isInit) {
            cancelAll();
            cancelCalls();
            isInit = true;
        }

        if (!Compatibility.isCompatible(9)) {
            searchNotificationPrimaryText(aContext);
        }
    }

    private Integer notificationPrimaryTextColor = null;

    private static String TO_SEARCH = "Search";

    // Retrieve notification textColor with android < 2.3
    @SuppressWarnings("deprecation")
    private void searchNotificationPrimaryText(Context aContext) {
        try {
            Notification ntf = new Notification();
            ntf.setLatestEventInfo(aContext, TO_SEARCH, "", null);
            LinearLayout group = new LinearLayout(aContext);
            ViewGroup event = (ViewGroup) ntf.contentView.apply(aContext, group);
            recurseSearchNotificationPrimaryText(event);
            group.removeAllViews();
        } catch (Exception e) {
            Log.e(THIS_FILE, "Can't retrieve the color", e);
        }
    }

    private boolean recurseSearchNotificationPrimaryText(ViewGroup gp) {
        final int count = gp.getChildCount();
        for (int i = 0; i < count; ++i) {
            if (gp.getChildAt(i) instanceof TextView) {
                final TextView text = (TextView) gp.getChildAt(i);
                final String szText = text.getText().toString();
                if (TO_SEARCH.equals(szText)) {
                    notificationPrimaryTextColor = text.getTextColors().getDefaultColor();
                    return true;
                }
            } else if (gp.getChildAt(i) instanceof ViewGroup) {
                if (recurseSearchNotificationPrimaryText((ViewGroup) gp.getChildAt(i))) {
                    return true;
                }
            }
        }
        return false;
    }

    // Foreground api

    private static final Class<?>[] SET_FG_SIG = new Class[] { boolean.class };
    private static final Class<?>[] START_FG_SIG = new Class[] { int.class, Notification.class };
    private static final Class<?>[] STOP_FG_SIG = new Class[] { boolean.class };
    private static final String THIS_FILE = "Notifications";

    private Method mSetForeground;
    private Method mStartForeground;
    private Method mStopForeground;
    private Object[] mSetForegroundArgs = new Object[1];
    private Object[] mStartForegroundArgs = new Object[2];
    private Object[] mStopForegroundArgs = new Object[1];

    private void invokeMethod(Method method, Object[] args) {
        try {
            method.invoke(context, args);
        } catch (InvocationTargetException e) {
            // Should not happen.
            Log.w(THIS_FILE, "Unable to invoke method", e);
        } catch (IllegalAccessException e) {
            // Should not happen.
            Log.w(THIS_FILE, "Unable to invoke method", e);
        }
    }

    /**
     * This is a wrapper around the new startForeground method, using the older
     * APIs if it is not available.
     */
    private void startForegroundCompat(int id, Notification notification) {
        // If we have the new startForeground API, then use it.
        if (mStartForeground != null) {
            mStartForegroundArgs[0] = Integer.valueOf(id);
            mStartForegroundArgs[1] = notification;
            invokeMethod(mStartForeground, mStartForegroundArgs);
            return;
        }

        // Fall back on the old API.
        mSetForegroundArgs[0] = Boolean.TRUE;
        invokeMethod(mSetForeground, mSetForegroundArgs);
        notificationManager.notify(id, notification);
    }

    /**
     * This is a wrapper around the new stopForeground method, using the older
     * APIs if it is not available.
     */
    private void stopForegroundCompat(int id) {
        // If we have the new stopForeground API, then use it.
        if (mStopForeground != null) {
            mStopForegroundArgs[0] = Boolean.TRUE;
            invokeMethod(mStopForeground, mStopForegroundArgs);
            return;
        }

        // Fall back on the old API. Note to cancel BEFORE changing the
        // foreground state, since we could be killed at that point.
        notificationManager.cancel(id);
        mSetForegroundArgs[0] = Boolean.FALSE;
        invokeMethod(mSetForeground, mSetForegroundArgs);
    }

    private boolean isServiceWrapper = false;

    public void onServiceCreate() {
        try {
            mStartForeground = context.getClass().getMethod("startForeground", START_FG_SIG);
            mStopForeground = context.getClass().getMethod("stopForeground", STOP_FG_SIG);
            isServiceWrapper = true;
            return;
        } catch (NoSuchMethodException e) {
            // Running on an older platform.
            mStartForeground = mStopForeground = null;
        }
        try {
            mSetForeground = context.getClass().getMethod("setForeground", SET_FG_SIG);
        } catch (NoSuchMethodException e) {
            throw new IllegalStateException("OS doesn't have Service.startForeground OR Service.setForeground!");
        }
        isServiceWrapper = true;
    }

    public void onServiceDestroy() {
        // Make sure our notification is gone.
        cancelAll();
        cancelCalls();
    }

    // Announces

    // Register
    public synchronized void notifyRegisteredAccounts(ArrayList<SipProfileState> activeAccountsInfos,
            boolean showNumbers) {
        if (!isServiceWrapper) {
            Log.e(THIS_FILE, "Trying to create a service notification from outside the service");
            System.out.println("SipNotifications class notifyRegisteredAccounts");

            return;
        }
        int icon = R.drawable.ic_stat_sipok;
        CharSequence tickerText = context.getString(R.string.service_ticker_registered_text);
        long when = System.currentTimeMillis();
        System.out.println("SipNotification synchronized");

        Builder nb = new NotificationCompat.Builder(context);
        nb.setSmallIcon(icon);
        nb.setTicker(tickerText);
        nb.setWhen(when);

        //Intent notificationIntent = new Intent(SipManager.ACTION_SIP_DIALER);
        Intent notificationIntent = new Intent("com.roamprocess1.roaming4world.R4wHome.R4w_ACTIVITY");
        notificationIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);

        System.out.println("SipNitification synchronized 1");
        PendingIntent contentIntent = PendingIntent.getActivity(context, 0, notificationIntent, 0);
        System.out.println("SipNitification synchronized 2");

        RegistrationNotification contentView = new RegistrationNotification(context.getPackageName());
        contentView.clearRegistrations();
        if (!Compatibility.isCompatible(9)) {
            contentView.setTextsColor(notificationPrimaryTextColor);
        }
        contentView.addAccountInfos(context, activeAccountsInfos);

        // notification.setLatestEventInfo(context, contentTitle,
        // contentText, contentIntent);
        nb.setOngoing(true);
        nb.setOnlyAlertOnce(true);
        nb.setContentIntent(contentIntent);
        nb.setContent(contentView);

        Notification notification = nb.build();
        notification.flags |= Notification.FLAG_NO_CLEAR;
        // We have to re-write content view because getNotification setLatestEventInfo implicitly
        notification.contentView = contentView;
        if (showNumbers) {
            // This only affects android 2.3 and lower
            notification.number = activeAccountsInfos.size();
        }
        startForegroundCompat(REGISTER_NOTIF_ID, notification);
    }

    /**
     * Format the remote contact name for the call info
     * @param callInfo the callinfo to format
     * @return the name to display for the contact
     */
    private String formatRemoteContactString(String remoteContact) {
        String formattedRemoteContact = remoteContact;
        if (resolveContacts) {
            CallerInfo callerInfo = CallerInfo.getCallerInfoFromSipUri(context, formattedRemoteContact);
            if (callerInfo != null && callerInfo.contactExists) {
                StringBuilder remoteInfo = new StringBuilder();
                remoteInfo.append(callerInfo.name);
                //remoteInfo.append(" <");
                //remoteInfo.append(SipUri.getCanonicalSipContact(remoteContact));
                //remoteInfo.append(">");
                formattedRemoteContact = remoteInfo.toString();
            }
        }
        return formattedRemoteContact;
    }

    /**
     * Format the notification title for a call info
     * @param title
     * @param callInfo
     * @return
     */
    private String formatNotificationTitle(int title, long accId) {
        StringBuilder notifTitle = new StringBuilder(context.getText(title));
        SipProfile acc = SipProfile.getProfileFromDbId(context, accId,
                new String[] { SipProfile.FIELD_DISPLAY_NAME });
        if ((acc != null) && !TextUtils.isEmpty(acc.display_name)) {

            System.out.println("SipNotifications account display   " + acc.display_name);
            notifTitle.append(" - ");
            notifTitle.append("Roaming4world");
        }
        return notifTitle.toString();
    }

    // Calls
    public void showNotificationForCall(SipCallSession callInfo) {
        // This is the pending call notification
        // int icon = R.drawable.ic_incall_ongoing;
        @SuppressWarnings("deprecation")
        int icon = android.R.drawable.stat_sys_phone_call;
        CharSequence tickerText = context.getText(R.string.ongoing_call);

        System.out.println("SipNotifications tickerText" + tickerText);
        long when = System.currentTimeMillis();

        if (inCallNotification == null) {
            inCallNotification = new NotificationCompat.Builder(context);
            inCallNotification.setSmallIcon(icon);
            inCallNotification.setTicker(tickerText);
            inCallNotification.setWhen(when);
            inCallNotification.setOngoing(true);
        }

        System.out.println("callInfo.getRemoteContact() ===" + callInfo.getRemoteContact());
        String[] parts = callInfo.getRemoteContact().split("@");

        String part1 = parts[0]; // 004
        String[] part3 = part1.split(":");
        System.out.println("part3==" + part3);
        String part4 = part3[0];
        System.out.println("part4 ==" + part4);
        String part5 = part3[1];
        System.out.println(" in side part5 ==" + part5);
        if (part5.startsWith("011")) {
            part5 = part5.substring(3);
        }
        System.out.println("showNotificationForCall");

        Intent notificationIntent = SipService.buildCallUiIntent(context, callInfo);
        PendingIntent contentIntent = PendingIntent.getActivity(context, 0, notificationIntent, 0);

        inCallNotification.setContentTitle(formatNotificationTitle(R.string.ongoing_call, callInfo.getAccId()));
        inCallNotification.setContentText(formatRemoteContactString(part5));
        inCallNotification.setContentIntent(contentIntent);

        Notification notification = inCallNotification.build();
        notification.flags |= Notification.FLAG_NO_CLEAR;
        notificationManager.notify(CALL_NOTIF_ID, notification);
    }

    public void showNotificationForMissedCall(ContentValues callLog) {
        int icon = android.R.drawable.stat_notify_missed_call;
        CharSequence tickerText = context.getText(R.string.missed_call);
        long when = System.currentTimeMillis();

        if (missedCallNotification == null) {
            missedCallNotification = new NotificationCompat.Builder(context);
            missedCallNotification.setSmallIcon(icon);
            missedCallNotification.setTicker(tickerText);
            missedCallNotification.setWhen(when);
            missedCallNotification.setOnlyAlertOnce(true);
            missedCallNotification.setAutoCancel(true);
            missedCallNotification.setDefaults(Notification.DEFAULT_ALL);
        }

        System.out.println("showNotificationForMissedCall");
        Intent notificationIntent = new Intent("com.roamprocess1.roaming4world.R4wHome.R4w_ACTIVITY");

        //   Intent notificationIntent = new Intent(SipManager.ACTION_SIP_CALLLOG);
        System.out.println("Misscall Notification");
        //notificationIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
        PendingIntent contentIntent = PendingIntent.getActivity(context, 0, notificationIntent, 0);

        String remoteContact = callLog.getAsString(CallLog.Calls.NUMBER);
        System.out.println("remoteContact  vlaue " + remoteContact);

        String[] parts = remoteContact.split("@");
        String part1 = parts[0]; // 004
        String[] part3 = part1.split(":");
        String part5 = part3[1];
        System.out.println("part5 ==" + part5);

        long accId = callLog.getAsLong(SipManager.CALLLOG_PROFILE_ID_FIELD);
        missedCallNotification.setContentTitle(formatNotificationTitle(R.string.missed_call, accId));
        missedCallNotification.setContentText(formatRemoteContactString(part5));
        System.out.println("remoteContact  vlaue ==" + remoteContact);
        missedCallNotification.setContentIntent(contentIntent);

        notificationManager.notify(CALLLOG_NOTIF_ID, missedCallNotification.build());
    }

    public void showNotificationForMessage(SipMessage msg) {
        if (!CustomDistribution.supportMessaging()) {
            return;
        }
        //CharSequence tickerText = context.getText(R.string.instance_message);

        if (!msg.getFrom().equalsIgnoreCase(viewingRemoteFrom)) {
            String from = formatRemoteContactString(msg.getFullFrom());

            if (from.equalsIgnoreCase(msg.getFullFrom())) {
                from = msg.getDisplayName() + " " + from;
            }

            String[] msgNumber = from.split("<");
            String msNumber = msgNumber[0];

            CharSequence tickerText = buildTickerMessage(context, msNumber, msg.getBody());

            if (messageNotification == null) {
                messageNotification = new NotificationCompat.Builder(context);
                messageNotification.setSmallIcon(
                        SipUri.isPhoneNumber(msNumber) ? R.drawable.r4wlogowhitefill : R.drawable.r4wlogowhitefill);

                String tick = tickerText.toString();

                if (tick.contains("\n")) {
                    String[] arr = tick.split("\n");
                    tick = arr[arr.length - 1];
                }

                if (tick.contains(imagefile)) {
                    String[] arr = tick.trim().split("@@");
                    arr = arr[1].split("-");
                    if (arr[0].equals("VID")) {
                        messageNotification.setTicker("Sent a video");
                    } else if (arr[0].equals("AUD")) {
                        messageNotification.setTicker("Sent an audio");
                    } else if (arr[0].equals("IMG")) {
                        messageNotification.setTicker("Sent an image");
                    } else if (arr[0].equals("CON")) {
                        messageNotification.setTicker("Sent a contact");
                    } else if (arr[0].equals("LOC")) {
                        messageNotification.setTicker("Sent a location");
                    }
                } else {
                    messageNotification.setTicker("Sent a message");
                }

                System.out.println("Tick==" + tick);

                messageNotification.setWhen(System.currentTimeMillis());
                messageNotification.setDefaults(Notification.DEFAULT_ALL);
                messageNotification.setAutoCancel(true);
                messageNotification.setOnlyAlertOnce(true);
            }

            Intent notificationIntent = new Intent(context, MessageActivity.class);
            System.out.println("msg.getFrom()   ==" + msg.getFrom() + " " + msg.getBody());

            notificationIntent.putExtra(SipMessage.FIELD_FROM, msg.getFrom());
            notificationIntent.putExtra(SipMessage.FIELD_BODY, msg.getBody());
            notificationIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            PendingIntent contentIntent = PendingIntent.getActivity(context, 0, notificationIntent,
                    PendingIntent.FLAG_CANCEL_CURRENT);
            String n = from;

            if (n.contains(" ")) {
                String[] nn = n.split(" ");
                n = nn[0];
            }

            messageNotification.setContentTitle(n);
            if (msg.getBody().toString().contains(imagefile)) {
                String[] arr = msg.getBody().toString().trim().split("@@");
                arr = arr[1].split("-");
                if (arr[0].equals("VID")) {
                    messageNotification.setTicker("Sent a video");
                } else if (arr[0].equals("AUD")) {
                    messageNotification.setTicker("Sent an audio");
                } else if (arr[0].equals("IMG")) {
                    messageNotification.setTicker("Sent an image");
                } else if (arr[0].equals("CON")) {
                    messageNotification.setTicker("Sent a contact");
                } else if (arr[0].equals("LOC")) {
                    messageNotification.setTicker("Sent a location");
                }
            } else {
                messageNotification.setContentText(msg.getBody());
            }
            messageNotification.setContentIntent(contentIntent);

            System.out.println("messageNotification.build() ==" + messageNotification.build() + "");

            if (!msg.getFrom().equals("sip:registrar@kamailio.org")
                    && !msg.getBody().contains("[Offline message -")) {
                notificationManager.notify(MESSAGE_NOTIF_ID, messageNotification.build());
            }
        }
    }

    public void showNotificationForVoiceMail(SipProfile acc, int numberOfMessages) {
        if (messageVoicemail == null) {

            messageVoicemail = new NotificationCompat.Builder(context);
            messageVoicemail.setSmallIcon(android.R.drawable.stat_notify_voicemail);
            messageVoicemail.setTicker(context.getString(R.string.voice_mail));
            messageVoicemail.setWhen(System.currentTimeMillis());
            messageVoicemail.setDefaults(Notification.DEFAULT_ALL);
            messageVoicemail.setAutoCancel(true);
            messageVoicemail.setOnlyAlertOnce(true);
        }

        PendingIntent contentIntent = null;
        Intent notificationIntent;
        if (acc != null && !TextUtils.isEmpty(acc.vm_nbr) && acc.vm_nbr != "null") {
            notificationIntent = new Intent(Intent.ACTION_CALL);
            notificationIntent.setData(
                    SipUri.forgeSipUri(SipManager.PROTOCOL_CSIP, acc.vm_nbr + "@" + acc.getDefaultDomain()));
            notificationIntent.putExtra(SipProfile.FIELD_ACC_ID, acc.id);
        } else {
            notificationIntent = new Intent(SipManager.ACTION_SIP_DIALER);
        }
        notificationIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        contentIntent = PendingIntent.getActivity(context, 0, notificationIntent,
                PendingIntent.FLAG_CANCEL_CURRENT);

        String messageText = "";
        if (acc != null) {
            messageText += acc.getProfileName() + " : ";
        }
        messageText += Integer.toString(numberOfMessages);

        messageVoicemail.setContentTitle(context.getString(R.string.voice_mail));

        System.out.println("SipNotifications  messageText  " + messageText);

        messageVoicemail.setContentText(messageText);
        if (contentIntent != null) {
            messageVoicemail.setContentIntent(contentIntent);
            notificationManager.notify(VOICEMAIL_NOTIF_ID, messageVoicemail.build());
        }
    }

    private static String viewingRemoteFrom = null;

    public void setViewingMessageFrom(String remoteFrom) {
        viewingRemoteFrom = remoteFrom;
    }

    protected static CharSequence buildTickerMessage(Context context, String address, String body) {
        String displayAddress = address;

        StringBuilder buf = new StringBuilder(
                displayAddress == null ? "" : displayAddress.replace('\n', ' ').replace('\r', ' '));
        buf.append(':').append(' ');

        int offset = buf.length();

        if (!TextUtils.isEmpty(body)) {
            body = body.replace('\n', ' ').replace('\r', ' ');
            buf.append(body);
        }

        SpannableString spanText = new SpannableString(buf.toString());
        spanText.setSpan(new StyleSpan(Typeface.BOLD), 0, offset, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);

        return spanText;
    }

    // Cancels
    public final void cancelRegisters() {
        if (!isServiceWrapper) {
            Log.e(THIS_FILE, "Trying to cancel a service notification from outside the service");
            return;
        }
        stopForegroundCompat(REGISTER_NOTIF_ID);
    }

    public final void cancelCalls() {
        notificationManager.cancel(CALL_NOTIF_ID);
    }

    public final void cancelMissedCalls() {
    }

    public final void cancelMessages() {
        notificationManager.cancel(MESSAGE_NOTIF_ID);
    }

    public final void cancelVoicemails() {
        notificationManager.cancel(VOICEMAIL_NOTIF_ID);
    }

    public final void cancelAll() {
        // Do not cancel calls notification since it's possible that there is
        // still an ongoing call.
        if (isServiceWrapper) {
            cancelRegisters();
        }
        cancelMessages();
        cancelMissedCalls();
        cancelVoicemails();
    }

}