/**
* 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.calllog;
import android.content.Context;
import android.content.res.Resources;
import android.database.Cursor;
import android.net.Uri;
import android.provider.CallLog;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.csipsimple.R;
import com.csipsimple.api.SipManager;
import com.csipsimple.api.SipUri;
import com.csipsimple.models.CallerInfo;
import com.csipsimple.utils.ContactsAsyncHelper;
/**
* Adapter class to fill in data for the Call Log.
*/
public class CallLogAdapter extends GroupingListAdapter
implements CallLogGroupBuilder.GroupCreator {
/** Interface used to initiate a refresh of the content. */
public interface CallFetcher {
void fetchCalls();
}
private final Context mContext;
private final CallFetcher mCallFetcher;
protected static final String THIS_FILE = "CallLogAdapter";
/** Instance of helper class for managing views. */
private final CallLogListItemHelper mCallLogViewsHelper;
/** Helper to set up contact photos. */
// private final ContactPhotoManager mContactPhotoManager;
/** Helper to group call log entries. */
private final CallLogGroupBuilder mCallLogGroupBuilder;
private OnCallLogAction callLogActionListener = null;
public void setOnCallLogActionListener(OnCallLogAction l) {
callLogActionListener = l;
}
public interface OnCallLogAction {
void viewDetails(int position, long[] callIds);
void placeCall(String number, Long accId);
}
private class CallRowInfos {
long[] callIds;
int position;
String number;
Long accId;
}
/** Listener for the primary action in the list, opens the call details. */
private final View.OnClickListener mPrimaryActionListener = new View.OnClickListener() {
@Override
public void onClick(View view) {
CallRowInfos cri = (CallRowInfos) view.getTag();
if (callLogActionListener != null) {
callLogActionListener.viewDetails(cri.position, cri.callIds);
}
}
};
/** Listener for the secondary action in the list, either call or play. */
private final View.OnClickListener mSecondaryActionListener = new View.OnClickListener() {
@Override
public void onClick(View view) {
CallRowInfos cri = (CallRowInfos) view.getTag();
if (callLogActionListener != null) {
callLogActionListener.placeCall(cri.number, cri.accId);
}
}
};
public CallLogAdapter(Context context, CallFetcher callFetcher) {
super(context);
mContext = context;
mCallFetcher = callFetcher;
Resources resources = mContext.getResources();
// mContactPhotoManager = ContactPhotoManager.getInstance(mContext);
PhoneCallDetailsHelper phoneCallDetailsHelper = new PhoneCallDetailsHelper(resources);
mCallLogViewsHelper = new CallLogListItemHelper(phoneCallDetailsHelper, context);
mCallLogGroupBuilder = new CallLogGroupBuilder(this);
}
/**
* Requery on background thread when {@link Cursor} changes.
*/
@Override
protected void onContentChanged() {
mCallFetcher.fetchCalls();
}
@Override
protected void addGroups(Cursor cursor) {
mCallLogGroupBuilder.addGroups(cursor);
}
@Override
public View newStandAloneView(Context context, ViewGroup parent) {
LayoutInflater inflater =
(LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View view = inflater.inflate(R.layout.call_log_list_item, parent, false);
findAndCacheViews(view);
return view;
}
@Override
public void bindStandAloneView(int position, View view, Context context, Cursor cursor) {
bindView(position, view, cursor, 1);
}
@Override
public View newChildView(Context context, ViewGroup parent) {
LayoutInflater inflater =
(LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View view = inflater.inflate(R.layout.call_log_list_item, parent, false);
findAndCacheViews(view);
return view;
}
@Override
public void bindChildView(int position, View view, Context context, Cursor cursor) {
bindView(position, view, cursor, 1);
}
@Override
public View newGroupView(Context context, ViewGroup parent) {
LayoutInflater inflater =
(LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View view = inflater.inflate(R.layout.call_log_list_item, parent, false);
findAndCacheViews(view);
return view;
}
@Override
public void bindGroupView(int position, View view, Context context, Cursor cursor,
int groupSize,
boolean expanded) {
bindView(position, view, cursor, groupSize);
}
private void findAndCacheViews(View view) {
// Get the views to bind to.
CallLogListItemViews views = CallLogListItemViews.fromView(view);
views.primaryActionView.setLongClickable(true);
views.primaryActionView.setOnClickListener(mPrimaryActionListener);
views.secondaryActionView.setOnClickListener(mSecondaryActionListener);
view.setTag(views);
}
/**
* Binds the views in the entry to the data in the call log.
*
* @param view the view corresponding to this entry
* @param c the cursor pointing to the entry in the call log
* @param count the number of entries in the current item, greater than 1 if
* it is a group
*/
private void bindView(int position, View view, Cursor c, int count) {
final CallLogListItemViews views = (CallLogListItemViews) view.getTag();
// Default case: an item in the call log.
views.primaryActionView.setVisibility(View.VISIBLE);
views.bottomDivider.setVisibility(isLastOfSection(c) ? View.GONE : View.VISIBLE);
int numberColIndex = c.getColumnIndex(CallLog.Calls.NUMBER);
int dateColIndex = c.getColumnIndex(CallLog.Calls.DATE);
int durationColIndex = c.getColumnIndex(CallLog.Calls.DURATION);
int accIdIndex = c.getColumnIndex(SipManager.CALLLOG_PROFILE_ID_FIELD);
// int typeColIndex = c.getColumnIndex(CallLog.Calls.TYPE);
String number = c.getString(numberColIndex);
final long date = c.getLong(dateColIndex);
final long duration = c.getLong(durationColIndex);
final Long accId = c.getLong(accIdIndex);
// final int callType = c.getInt(typeColIndex);
// final CallerInfo cachedContactInfo = getContactInfoFromCallLog(c);
CallRowInfos cri = new CallRowInfos();
cri.callIds = getCallIds(c, count);
cri.position = position;
cri.number = number;
cri.accId = accId;
views.primaryActionView.setTag(cri);
views.secondaryActionView.setTag(cri);
views.secondaryActionView.setVisibility(TextUtils.isEmpty(number) ? View.GONE
: View.VISIBLE);
String cachedNumber = (String) view.getTag(R.id.number);
if (cachedNumber != null && cachedNumber.equals(number)) {
// No need to go set details about the contact again this has
// already been done
return;
}
CallerInfo info = CallerInfo.getCallerInfoFromSipUri(mContext, number);
final Uri lookupUri = info.contactContentUri;
final String name = info.name;
final int ntype = info.numberType;
final String label = info.phoneLabel;
CharSequence formattedNumber = SipUri.getCanonicalSipContact(number, false);
final int[] callTypes = getCallTypes(c, count);
PhoneCallDetails details;
if (TextUtils.isEmpty(name)) {
details = new PhoneCallDetails(number, formattedNumber,
callTypes, date, duration);
} else {
// We do not pass a photo id since we do not need the high-res
// picture.
details = new PhoneCallDetails(number, formattedNumber,
callTypes, date, duration, name, ntype, label, lookupUri, null);
}
mCallLogViewsHelper.setPhoneCallDetails(views, details);
setPhoto(views, info);
}
/** Returns true if this is the last item of a section. */
private boolean isLastOfSection(Cursor c) {
if (c.isLast()) {
return true;
}
return false;
}
/**
* Returns the call types for the given number of items in the cursor.
* <p>
* It uses the next {@code count} rows in the cursor to extract the types.
* <p>
* It position in the cursor is unchanged by this function.
*/
private int[] getCallTypes(Cursor cursor, int count) {
int position = cursor.getPosition();
int[] callTypes = new int[count];
for (int index = 0; index < count; ++index) {
callTypes[index] = cursor.getInt(cursor.getColumnIndex(CallLog.Calls.TYPE));
cursor.moveToNext();
}
cursor.moveToPosition(position);
return callTypes;
}
/**
* Retrieve call ids list of the item at a given position
*
* @param position the position to look at
* @return the list of call ids
*/
public long[] getCallIdsAtPosition(int position) {
Cursor item = (Cursor) getItem(position);
int count = getGroupSize(position);
return getCallIds(item, count);
}
/**
* Returns the call ids for the given number of items in the cursor.
* <p>
* It uses the next {@code count} rows in the cursor to extract the types.
* <p>
* It position in the cursor is unchanged by this function.
*/
private long[] getCallIds(Cursor cursor, int count) {
int position = cursor.getPosition();
long[] callIds = new long[count];
for (int index = 0; index < count; ++index) {
if(!cursor.isAfterLast()) {
callIds[index] = cursor.getLong(cursor.getColumnIndex(CallLog.Calls._ID));
}
cursor.moveToNext();
}
cursor.moveToPosition(position);
return callIds;
}
/**
* Retrieve the remote sip uri for a call log at the given position
* @param position the position to look at
* @return the sip uri
*/
public String getCallRemoteAtPostion(int position) {
Cursor item = (Cursor) getItem(position);
if(item != null) {
String number = item.getString(item.getColumnIndex(CallLog.Calls.NUMBER));
return SipUri.getCanonicalSipContact(number, false);
}
return "";
}
private void setPhoto(CallLogListItemViews views, CallerInfo ci) {
views.quickContactView.assignContactUri(ci.contactContentUri);
ContactsAsyncHelper.updateImageViewWithContactPhotoAsync(mContext, views.quickContactView
.getImageView(),
ci,
R.drawable.ic_contact_picture_holo_dark);
}
@Override
public void addGroup(int cursorPosition, int size, boolean expanded) {
super.addGroup(cursorPosition, size, expanded);
}
}