/**
* 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.ui.favorites;
import android.content.Context;
import android.database.ContentObserver;
import android.database.Cursor;
import android.database.MatrixCursor;
import android.database.MergeCursor;
import android.provider.BaseColumns;
import android.support.v4.content.AsyncTaskLoader;
import android.text.TextUtils;
import com.csipsimple.api.SipProfile;
import com.csipsimple.utils.contacts.ContactsWrapper;
import java.util.ArrayList;
public class FavLoader extends AsyncTaskLoader<Cursor> {
private Cursor currentResult;
public FavLoader(Context context) {
super(context);
}
private ContentObserver loaderObserver = new ForceLoadContentObserver();
@Override
public Cursor loadInBackground() {
// First of all, get all active accounts
ArrayList<SipProfile> accounts = SipProfile.getAllProfiles(getContext(), true,
new String[] {
SipProfile.FIELD_ID,
SipProfile.FIELD_ACC_ID,
SipProfile.FIELD_ACTIVE,
SipProfile.FIELD_DISPLAY_NAME,
SipProfile.FIELD_WIZARD,
SipProfile.FIELD_PRIORITY,
SipProfile.FIELD_ANDROID_GROUP,
SipProfile.FIELD_PUBLISH_ENABLED,
SipProfile.FIELD_REG_URI,
SipProfile.FIELD_PROXY
});
Cursor[] cursorsToMerge = new Cursor[2 * accounts.size()];
int i = 0;
for (SipProfile acc : accounts) {
cursorsToMerge[i++] = createHeaderCursorFor(acc);
cursorsToMerge[i++] = createContentCursorFor(acc);
}
getContext().getContentResolver().registerContentObserver(SipProfile.ACCOUNT_STATUS_URI,
true, loaderObserver);
if(cursorsToMerge.length > 0) {
MergeCursor mg = new MergeCursor(cursorsToMerge);
mg.registerContentObserver(loaderObserver);
return mg;
}else {
return null;
}
}
/**
* Called when there is new data to deliver to the client. The super class
* will take care of delivering it; the implementation here just adds a
* little more logic.
*/
@Override
public void deliverResult(Cursor c) {
if (isReset()) {
// An async query came in while the loader is stopped. We
// don't need the result.
if (currentResult != null) {
onReleaseResources(currentResult);
}
}
currentResult = c;
if (isStarted()) {
// If the Loader is currently started, we can immediately
// deliver its results.
super.deliverResult(c);
}
}
/**
* Handles a request to start the Loader.
*/
@Override
protected void onStartLoading() {
if (currentResult != null && !takeContentChanged()) {
// If we currently have a result available, deliver it
// immediately.
deliverResult(currentResult);
}else {
forceLoad();
}
}
/**
* Handles a request to stop the Loader.
*/
@Override
protected void onStopLoading() {
// Attempt to cancel the current load task if possible.
cancelLoad();
}
/**
* Handles a request to cancel a load.
*/
@Override
public void onCanceled(Cursor c) {
super.onCanceled(c);
// At this point we can release the resources associated with 'apps'
// if needed.
onReleaseResources(c);
}
/**
* Handles a request to completely reset the Loader.
*/
@Override
protected void onReset() {
super.onReset();
// Ensure the loader is stopped
onStopLoading();
// At this point we can release the resources associated with 'apps'
// if needed.
if (currentResult != null) {
onReleaseResources(currentResult);
currentResult = null;
}
}
/**
* Helper function to take care of releasing resources associated with an
* actively loaded data set.
*/
protected void onReleaseResources(Cursor c) {
if(c != null) {
c.unregisterContentObserver(loaderObserver);
c.close();
}
getContext().getContentResolver().unregisterContentObserver(loaderObserver);
}
/**
* Creates a cursor that contains a single row and maps the section to the
* given value.
*/
private Cursor createHeaderCursorFor(SipProfile account) {
MatrixCursor matrixCursor =
new MatrixCursor(new String[] {
BaseColumns._ID,
ContactsWrapper.FIELD_TYPE,
SipProfile.FIELD_DISPLAY_NAME,
SipProfile.FIELD_WIZARD,
SipProfile.FIELD_ANDROID_GROUP,
SipProfile.FIELD_PUBLISH_ENABLED,
SipProfile.FIELD_REG_URI,
SipProfile.FIELD_PROXY,
SipProfile.FIELD_ACC_ID
});
String proxies = "";
if(account.proxies != null) {
proxies = TextUtils.join(SipProfile.PROXIES_SEPARATOR, account.proxies);
}
matrixCursor.addRow(new Object[] {
account.id,
ContactsWrapper.TYPE_GROUP,
account.display_name,
account.wizard,
account.android_group,
account.publish_enabled,
account.reg_uri,
proxies,
account.acc_id
});
return matrixCursor;
}
/**
* Creates a cursor that contains contacts group corresponding to an sip
* account.
*/
private Cursor createContentCursorFor(SipProfile account) {
Cursor c = null;
if(!TextUtils.isEmpty(account.android_group)) {
c = ContactsWrapper.getInstance().getContactsByGroup(getContext(), account.android_group);
}
if(c != null) {
return c;
}
MatrixCursor mc = new MatrixCursor (new String[] {
BaseColumns._ID,
ContactsWrapper.FIELD_TYPE
});
mc.addRow(new Object[] {account.id, ContactsWrapper.TYPE_CONFIGURE});
return mc;
}
}