/** * 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.csipsimple.service; import android.database.ContentObserver; import android.database.Cursor; import android.os.Handler; import com.csipsimple.api.SipManager; import com.csipsimple.api.SipProfile; import com.csipsimple.service.SipService.SameThreadException; import com.csipsimple.service.SipService.SipRunnable; import com.csipsimple.utils.AccountListUtils; import com.csipsimple.utils.AccountListUtils.AccountStatusDisplay; import com.csipsimple.utils.Log; import com.csipsimple.utils.contacts.ContactsWrapper; import java.util.ArrayList; import java.util.List; public class PresenceManager { private static final String THIS_FILE = "PresenceManager"; private static final String[] ACC_PROJECTION = new String[] { SipProfile.FIELD_ID, SipProfile.FIELD_DISPLAY_NAME, SipProfile.FIELD_WIZARD }; private SipService service; private final Handler mHandler = new Handler(); private ArrayList<SipProfile> addedAccounts = new ArrayList<SipProfile>(); private AccountStatusContentObserver statusObserver; public synchronized void startMonitoring(SipService srv) { service = srv; if(statusObserver == null) { statusObserver = new AccountStatusContentObserver(mHandler); service.getContentResolver().registerContentObserver(SipProfile.ACCOUNT_STATUS_URI, true, statusObserver); } } public synchronized void stopMonitoring() { if (statusObserver != null) { service.getContentResolver().unregisterContentObserver(statusObserver); statusObserver = null; } service = null; } /** * Get buddies sip uris associated with a sip profile * @param acc the profile to search in * @return a list of sip uris */ private synchronized List<String> getBuddiesForAccount(SipProfile acc){ if(service != null) { return ContactsWrapper.getInstance().getCSipPhonesByGroup(service, acc.display_name); }else { return new ArrayList<String>(); } } /** * Add buddies for a given account * @param acc */ private synchronized void addBuddiesForAccount(SipProfile acc) { // Get buddies uris for this account final List<String> toAdd = getBuddiesForAccount(acc); if (toAdd.size() > 0 && service != null) { service.getExecutor().execute(new SipRunnable() { @Override protected void doRun() throws SameThreadException { for (String csipUri : toAdd) { service.addBuddy("sip:" + csipUri); } } }); } addedAccounts.add(acc); } /** * Delete buddies for a given account * @param acc */ private synchronized void deleteBuddiesForAccount(SipProfile acc) { // Get buddies uris for this account final List<String> toDel = getBuddiesForAccount(acc); if (toDel.size() > 0 && service != null) { for (String csipUri : toDel) { ContactsWrapper.getInstance().updateCSipPresence(service, csipUri, SipManager.PresenceStatus.UNKNOWN, ""); } service.getExecutor().execute(new SipRunnable() { @Override protected void doRun() throws SameThreadException { if(service != null) { for (String csipUri : toDel) { service.removeBuddy("sip:" + csipUri); } } } }); } // Find the correct account to remove int toRemoveIndex = -1; for(int idx = 0; idx < addedAccounts.size(); idx++) { SipProfile existingAcc = addedAccounts.get(idx); if(existingAcc.id == acc.id) { toRemoveIndex = idx; break; } } if(toRemoveIndex >= 0) { addedAccounts.remove(toRemoveIndex); } } /** * Update internal state of registered account * Push buddies for registered account * Remove buddies for offline accounts */ private synchronized void updateRegistrations() { if(service == null) { // Nothing to do at this point return; } Cursor c = service.getContentResolver().query(SipProfile.ACCOUNT_URI, ACC_PROJECTION, SipProfile.FIELD_ACTIVE + "=?", new String[] { "1" }, null); ArrayList<SipProfile> accToAdd = new ArrayList<SipProfile>(); ArrayList<SipProfile> accToRemove = new ArrayList<SipProfile>(); ArrayList<Long> alreadyAddedAcc = new ArrayList<Long>(); for (SipProfile addedAcc : addedAccounts) { alreadyAddedAcc.add(addedAcc.id); } // Decide which accounts should be removed, added, left unchanged if (c != null && c.getCount() > 0) { try { if (c.moveToFirst()) { do { final SipProfile acc = new SipProfile(c); AccountStatusDisplay accountStatusDisplay = AccountListUtils .getAccountDisplay(service, acc.id); if (accountStatusDisplay.availableForCalls) { if (!alreadyAddedAcc.contains(acc.id)) { accToAdd.add(acc); } } else { if (alreadyAddedAcc.contains(acc.id)) { accToRemove.add(acc); } } } while (c.moveToNext()); } } catch (Exception e) { Log.e(THIS_FILE, "Error on looping over sip profiles", e); } finally { c.close(); } }else if(c != null) { c.close(); } for(SipProfile acc : accToRemove) { deleteBuddiesForAccount(acc); } for(SipProfile acc : accToAdd) { addBuddiesForAccount(acc); } } /** * Observer for changes of account registration status */ class AccountStatusContentObserver extends ContentObserver { public AccountStatusContentObserver(Handler h) { super(h); } public void onChange(boolean selfChange) { updateRegistrations(); } } /** * Forward status change for a buddy to manager * @param buddyUri buddy uri * @param monitorPres whether the status is currently monitored * @param presStatus the status * @param statusText the text representing this status */ public void changeBuddyState(String buddyUri, int monitorPres, SipManager.PresenceStatus presStatus, String statusText) { if(service != null) { ContactsWrapper.getInstance().updateCSipPresence(service, buddyUri.replace("sip:", ""), presStatus, statusText); } } }