package com.orangelabs.rcs.provider.ipcall;
import java.util.Calendar;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import com.orangelabs.rcs.core.content.MmContent;
import com.orangelabs.rcs.provider.settings.RcsSettings;
import com.orangelabs.rcs.utils.PhoneUtils;
import com.orangelabs.rcs.utils.logger.Logger;
/**
* IP call history. This content provider removes old messages if there is no enough space.
*
* @author owom5460
*/
public class IPCall {
/**
* Current instance
*/
private static IPCall instance = null;
/**
* Content resolver
*/
private ContentResolver cr;
/**
* Database URI
*/
private Uri databaseUri = IPCallData.CONTENT_URI;
/**
* Max log entries
*/
private int maxLogEntries;
/**
* The logger
*/
private Logger logger = Logger.getLogger(this.getClass().getName());
/**
* Create instance
*
* @param ctx Context
*/
public static synchronized void createInstance(Context ctx) {
if (instance == null) {
instance = new IPCall(ctx);
}
}
/**
* Returns instance
*
* @return Instance
*/
public static IPCall getInstance() {
return instance;
}
/**
* Constructor
*
* @param ctx Application context
*/
private IPCall(Context ctx) {
super();
this.cr = ctx.getContentResolver();
this.maxLogEntries = RcsSettings.getInstance().getMaxIPCallLogEntriesPerContact();
}
/**
* Add a new entry in the call history
*
* @param contact Remote contact
* @param sessionId Session ID
* @param event_type IPCall event type
* @param content audio content
* @param content video content
* @param status Call status
*/
public Uri addCall(String contact, String sessionId, int event_type, MmContent audiocontent, MmContent videocontent, int status) {
if(logger.isActivated()){
logger.debug("Add new call entry for contact " + contact + ": session=" + sessionId + ", status=" + status);
}
contact = PhoneUtils.extractNumberFromUri(contact);
ContentValues values = new ContentValues();
values.put(IPCallData.KEY_SESSION_ID, sessionId);
values.put(IPCallData.KEY_CONTACT, contact);
values.put(IPCallData.KEY_EVENT_TYPE, event_type);
String audioEncoding = (audiocontent == null)? "":audiocontent.getEncoding();
values.put(IPCallData.KEY_AUDIO_MIME_TYPE, audioEncoding);
String videoEncoding = (videocontent == null)? "":videocontent.getEncoding();
values.put(IPCallData.KEY_VIDEO_MIME_TYPE, videoEncoding);
values.put(IPCallData.KEY_TIMESTAMP, Calendar.getInstance().getTimeInMillis());
values.put(IPCallData.KEY_NUMBER_MESSAGES, purge(contact)+1);
values.put(IPCallData.KEY_STATUS, status);
return cr.insert(databaseUri, values);
}
/**
* Purge older calls. The first call is removed if no enough place for new calls.
*
* @param contact Contact id
* @return the new number a call rows after recycling (normally: current-1)
*/
private int purge(String contact){
// Get first and last message dates for the contact
Cursor extrem = cr.query(databaseUri, new String[] {
"min("+IPCallData.KEY_TIMESTAMP+")",
"max("+IPCallData.KEY_TIMESTAMP+")"},
IPCallData.KEY_CONTACT +" = \'"+contact+"\'", null, null);
long minDate = -1 ,maxDate = -1;
if (extrem.moveToFirst()) {
minDate = extrem.getLong(0);
maxDate = extrem.getLong(1);
}
extrem.close();
if (logger.isActivated()) {
logger.debug("Recycler: minDate=" + minDate + ", maxDate=" + maxDate);
}
// If no entry for this contact return 0
if (minDate == -1 && maxDate == -1) {
return 0;
}
// Get the current number of messages in the database for the contact */
Cursor c = cr.query(databaseUri, new String[] {
IPCallData.KEY_NUMBER_MESSAGES},
IPCallData.KEY_CONTACT + " = \'" + contact + "\'"
+" AND "+ IPCallData.KEY_TIMESTAMP + " = " + maxDate,
null,
null);
int numberOfMessagesForContact = 0;
if (c.moveToFirst()) {
numberOfMessagesForContact = c.getInt(0);
if(logger.isActivated()){
logger.debug("Recycler : number of messages for this contact = "+numberOfMessagesForContact);
}
if(numberOfMessagesForContact<maxLogEntries){
/* Enough place for another message... do nothing return */
if(logger.isActivated()){
logger.debug("Recycler : Enough place for another message, do nothing return");
}
c.close();
return numberOfMessagesForContact;
}
if(logger.isActivated()){
logger.debug("Recycler : Not enough place for another message, we will have to remove something");
}
/* Not enough place for another message... we will have to remove something (the older one) */
int removedMessages = cr.delete(databaseUri,
IPCallData.KEY_CONTACT +" = \'"+contact+"\'"
+" AND "+IPCallData.KEY_TIMESTAMP+ " = "+minDate, null);
if(logger.isActivated()){
logger.debug("Recycler : messages removed : "+removedMessages);
}
/* We also will have to set the new number of messages after removing, for the last entry */
ContentValues values = new ContentValues();
numberOfMessagesForContact-=removedMessages;
if(logger.isActivated()){
logger.debug("Recycler : new number of message after deletion : "+numberOfMessagesForContact);
}
/*
* It 's pretty useless to do the following because normally,
* the next entry would be add with the good number after existing recycler.
* But if this function is used externally just for recycling, let's do it...
*/
values.put(IPCallData.KEY_NUMBER_MESSAGES, numberOfMessagesForContact);
int updatedRows = cr.update(databaseUri, values,
IPCallData.KEY_CONTACT +" = \'"+contact+"\' "
+" AND "+IPCallData.KEY_TIMESTAMP+ " = "+maxDate, null);
if(logger.isActivated()){
logger.debug("Recycler : updated rows for the contact (must be 1 or 0 if no more messages) : "+updatedRows);
}
}
c.close();
return numberOfMessagesForContact;
}
/**
* Delete entry from its date in the call history
*
* @param contact Contact id
* @param date Date
*/
public void removeCall(String contact, long date) {
if (logger.isActivated()) {
logger.debug("Delete call for contact " + contact + " at date " + date);
}
// Count entries to be deleted
Cursor count = cr.query(databaseUri, null,
IPCallData.KEY_CONTACT + " = \'"+ contact+"\'"
+ " AND "+ IPCallData.KEY_TIMESTAMP+ " = "+ date,
null,
null);
int toBeDeletedRows = count.getCount();
count.close();
if (toBeDeletedRows == 0) {
if (logger.isActivated()) {
logger.debug("No entry to be deleted");
}
return;
}
if (logger.isActivated()) {
logger.debug("DeleteCall: rows to be deleted (should be 1): "+toBeDeletedRows);
}
// Manage recycling
Cursor c = cr.query(databaseUri, new String[]{
IPCallData.KEY_TIMESTAMP,
IPCallData.KEY_NUMBER_MESSAGES},
IPCallData.KEY_CONTACT+" = \'"+contact+"\'",
null, IPCallData.KEY_TIMESTAMP + " DESC");
if (c.moveToFirst()) {
long maxDate = c.getLong(0);
int numberForLast = c.getInt(1);
ContentValues values = new ContentValues();
values.put(IPCallData.KEY_NUMBER_MESSAGES, numberForLast-toBeDeletedRows);
// If last entry for this contact equals to this csh message
if (date==maxDate) {
// Update the previous one
if(c.moveToNext()){
maxDate = c.getLong(0);
}
}
// If no more message exists after deleting this one for this contact, the
// update is useless because it will be made on the message to be deleted.
int updatedRows = cr.update(databaseUri, values,
IPCallData.KEY_TIMESTAMP+ " = "+maxDate
+" AND "+IPCallData.KEY_CONTACT+" = \'"+contact+"\'", null);
if(logger.isActivated()){
logger.debug("DeleteCall : recycling updated rows (should be 1) : "+updatedRows);
}
}
c.close();
int deletedRows = cr.delete(databaseUri,
IPCallData.KEY_CONTACT + " = \'"+ contact+"\'"
+ " AND "+ IPCallData.KEY_TIMESTAMP+ " = "+ date, null);
if(logger.isActivated()){
logger.debug("DeleteCall : deleted rows (should be 1) : "+deletedRows);
}
}
/**
* Update the status of an entry in the call history
*
* @param sessionId Session ID of the entry
* @param status New status
*/
public void setStatus(String sessionId, int status) {
if (logger.isActivated()) {
logger.debug("Update status of session " + sessionId + " to " + status);
}
ContentValues values = new ContentValues();
values.put(IPCallData.KEY_STATUS, status);
cr.update(databaseUri, values, IPCallData.KEY_SESSION_ID + " = " + sessionId, null);
}
}