/**
* 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.outgoingcall;
import android.app.PendingIntent;
import android.app.PendingIntent.CanceledException;
import android.database.Cursor;
import android.os.Bundle;
import android.os.RemoteException;
import android.support.v4.content.Loader;
import android.view.View;
import android.widget.ListView;
import com.csipsimple.api.ISipService;
import com.csipsimple.api.SipProfile;
import com.csipsimple.ui.account.AccountsLoader;
import com.csipsimple.utils.CallHandlerPlugin;
import com.csipsimple.utils.Log;
import com.csipsimple.widgets.CSSListFragment;
public class OutgoingCallListFragment extends CSSListFragment {
private static final String THIS_FILE = "OutgoingCallListFragment";
private OutgoingAccountsAdapter mAdapter;
private AccountsLoader accLoader;
private long startDate;
private boolean callMade = false;
@Override
public void onCreate(Bundle state) {
super.onCreate(state);
setHasOptionsMenu(true);
}
@Override
public void onResume() {
super.onResume();
callMade = false;
attachAdapter();
getLoaderManager().initLoader(0, null, this);
startDate = System.currentTimeMillis();
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
}
private void attachAdapter() {
if(getListAdapter() == null) {
if(mAdapter == null) {
mAdapter = new OutgoingAccountsAdapter(this, null);
}
setListAdapter(mAdapter);
}
}
@Override
public Loader<Cursor> onCreateLoader(int loader, Bundle args) {
OutgoingCallChooser superActivity = ((OutgoingCallChooser) getActivity());
accLoader = new AccountsLoader(getActivity(), superActivity.getPhoneNumber(), superActivity.shouldIgnoreRewritingRules());
return accLoader;
}
final long MOBILE_CALL_DELAY_MS = 600;
/**
* Place the call for a given cursor positionned at right index in list
* @param c The cursor pointing the entry we'd like to call
* @return true if call performed, false else
*/
private boolean placeCall(Cursor c) {
OutgoingCallChooser superActivity = ((OutgoingCallChooser)getActivity());
ISipService service = superActivity.getConnectedService();
long accountId = c.getLong(c.getColumnIndex(SipProfile.FIELD_ID));
if(accountId > SipProfile.INVALID_ID) {
// Extra check for the account id.
if(service == null) {
return false;
}
boolean canCall = c.getInt(c.getColumnIndex(AccountsLoader.FIELD_STATUS_OUTGOING)) == 1;
if(!canCall) {
return false;
}
try {
String toCall = c.getString(c.getColumnIndex(AccountsLoader.FIELD_NBR_TO_CALL));
service.makeCall(toCall, (int) accountId);
if(superActivity != null) {
superActivity.finishServiceIfNeeded(true);
}
return true;
} catch (RemoteException e) {
Log.e(THIS_FILE, "Unable to make the call", e);
}
}else if(accountId < SipProfile.INVALID_ID) {
// This is a plugin row.
if(accLoader != null) {
CallHandlerPlugin ch = accLoader.getCallHandlerWithAccountId(accountId);
if(ch == null) {
Log.w(THIS_FILE, "Call handler not anymore available in loader... something gone wrong");
return false;
}
String nextExclude = ch.getNextExcludeTelNumber();
long delay = 0;
if (nextExclude != null && service != null) {
try {
service.ignoreNextOutgoingCallFor(nextExclude);
} catch (RemoteException e) {
Log.e(THIS_FILE, "Ignore next outgoing number failed");
}
delay = MOBILE_CALL_DELAY_MS - (System.currentTimeMillis() - startDate);
}
if(ch.getIntent() != null) {
PluginCallRunnable pendingTask = new PluginCallRunnable(ch.getIntent(), delay);
Log.d(THIS_FILE, "Deferring call task of " + delay);
pendingTask.start();
}
return true;
}
}
return false;
}
private class PluginCallRunnable extends Thread {
private PendingIntent pendingIntent;
private long delay;
public PluginCallRunnable(PendingIntent pi, long d) {
pendingIntent = pi;
delay = d;
}
@Override
public void run() {
if(delay > 0) {
try {
sleep(delay);
} catch (InterruptedException e) {
Log.e(THIS_FILE, "Thread that fires outgoing call has been interrupted");
}
}
OutgoingCallChooser superActivity = ((OutgoingCallChooser)getActivity());
try {
pendingIntent.send();
} catch (CanceledException e) {
Log.e(THIS_FILE, "Pending intent cancelled", e);
}
if(superActivity != null) {
superActivity.finishServiceIfNeeded(false);
}
}
}
@Override
public synchronized void changeCursor(Cursor c) {
if(c != null && callMade == false) {
OutgoingCallChooser superActivity = ((OutgoingCallChooser)getActivity());
Long accountToCall = superActivity.getAccountToCallTo();
boolean canCallOtherAccounts = superActivity.canCallAutomatically();
// Move to first to search in this cursor
c.moveToFirst();
// If only one is available.
// We don't use this filter if account were specified.
if(c.getCount() == 1 && canCallOtherAccounts) {
if(placeCall(c)) {
c.close();
callMade = true;
return;
}
}else {
do {
if(accountToCall != SipProfile.INVALID_ID) {
// It's account that was asked to call
if(accountToCall == c.getLong(c.getColumnIndex(SipProfile.FIELD_ID))) {
if(placeCall(c)) {
c.close();
callMade = true;
return;
}
}
} else if((c.getInt(c.getColumnIndex(AccountsLoader.FIELD_FORCE_CALL)) == 1) && canCallOtherAccounts) {
// If one with forceCall flag
// We don't use this filter if account were specified.
if(placeCall(c)) {
c.close();
callMade = true;
return;
}
}
} while(c.moveToNext());
}
}
// Set adapter content if nothing to force was found
if(mAdapter != null) {
mAdapter.changeCursor(c);
}
}
@Override
public synchronized void onListItemClick(ListView l, View v, int position, long id) {
if(mAdapter != null) {
placeCall((Cursor) mAdapter.getItem(position));
}
}
public AccountsLoader getAccountLoader() {
return accLoader;
}
}