重新设计实现CSipSimple呼叫记录分组功能

CSipSimple 原有的分组功能只能针对连续相同被叫号码,如果中间有间隔,相同的号码就不会被分成一组。这个实现很弱,也失去了分组的意义。下面针对这块功能的设计实现做下简单记录。

1. 自己封装一个CursorLoader

这里取名为CalllogCursorLoader,在CallLogListFragment -> OnCreateLoader中:

    // Loader
    public Loader<Cursor> onCreateLoader(int id, Bundle args) {
    	return new CalllogCursorLoader(getActivity());
    }

2. CalllogCursorLoader.java 代码:

package org.phoneos.db;

import org.phoneos.api.SipManager;

import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.provider.CallLog;
import android.support.v4.content.AsyncTaskLoader;

public class CalllogCursorLoader extends AsyncTaskLoader<Cursor> {
	final ForceLoadContentObserver mObserver;
	private FastCursor fastCursor = null;
	private Cursor mObserverCursor = null;

	/**
	 * Creates an empty unspecified CursorLoader. You must follow this with
	 * calls to {@link #setUri(Uri)}, {@link #setSelection(String)}, etc to
	 * specify the query to perform.
	 */
	public CalllogCursorLoader(Context context) {
		super(context);
		mObserver = new ForceLoadContentObserver();
	}

	/* Runs on a worker thread */
	@Override
	public Cursor loadInBackground() {

		String[] fields = new String[] { CallLog.Calls._ID,
				CallLog.Calls.CACHED_NAME, CallLog.Calls.CACHED_NUMBER_LABEL,
				CallLog.Calls.CACHED_NUMBER_TYPE, CallLog.Calls.DURATION,
				CallLog.Calls.DATE, CallLog.Calls.NEW, CallLog.Calls.NUMBER,
				CallLog.Calls.TYPE, SipManager.CALLLOG_PROFILE_ID_FIELD };

		try {
			if (mObserverCursor != null) {
				mObserverCursor.close();
				mObserverCursor = null;
			}
			
			// get last inserted, a trick for observer data
			mObserverCursor = getContext().getContentResolver().query(
					SipManager.CALLLOG_URI, fields, null, null,
					"date desc limit 1");

			if (mObserverCursor != null) {
				mObserverCursor.registerContentObserver(mObserver);
			}

//			if (fastCursor == null) {
			Cursor cursor = getContext().getContentResolver().query(
					SipManager.CALLLOG_URI, fields, null, null, "date asc");

			fastCursor = new FastCursor(cursor);

			cursor.close();
			cursor = null;

//			} else {
//				fastCursor.addCursor(mObserverCursor);
//			}

//			int min = fastCursor.getCount();
//			if (min > 100)
//				min = 100;
//			for (int i = 0; i < min; i++) {
//				fastCursor.moveToPosition(i);
//				Log.d("LOADER", i + ", " + fastCursor.getString(fastCursor.getColumnIndex(CallLog.Calls.NUMBER)));
//			}

			return fastCursor;
		} finally {
		}
	}

	/* Runs on the UI thread */
	@Override
	public void deliverResult(Cursor cursor) {
		if (isReset()) {
			if (fastCursor != null) {
				fastCursor.close();
			}
		}
		
		Cursor oldCursor = fastCursor;
		fastCursor = (FastCursor)cursor;
		
		if (isStarted()) {
			super.deliverResult(cursor);
		}

		if (oldCursor != null && oldCursor != cursor && !oldCursor.isClosed()) {
			oldCursor.close();
		}
	}

	/**
	 * Starts an asynchronous load of the contacts list data. When the result is
	 * ready the callbacks will be called on the UI thread. If a previous load
	 * has been completed and is still valid the result may be passed to the
	 * callbacks immediately.
	 * 
	 * Must be called from the UI thread
	 */
	@Override
	protected void onStartLoading() {
		if (fastCursor != null) {
			deliverResult(fastCursor);
		}

		if (takeContentChanged() || fastCursor == null) {
			forceLoad();
		}
	}

	/**
	 * Must be called from the UI thread
	 */
	@Override
	protected void onStopLoading() {
		// Attempt to cancel the current load task if possible.
		cancelLoad();
	}
	
	@Override
	public void onCanceled(Cursor data) {
		if (fastCursor != null && !fastCursor.isClosed()) {
			fastCursor.close();
		}
	}

	@Override
	protected void onReset() {
		super.onReset();
		// Ensure the loader is stopped
		onStopLoading();

		if (fastCursor != null && !fastCursor.isClosed()) {
			fastCursor.close();
		}

		fastCursor = null;
	}
	
}

3. FastCursor.java 代码:

package org.phoneos.db;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;

import android.database.AbstractCursor;
import android.database.Cursor;
import android.database.MatrixCursor;
import android.provider.CallLog;
import android.util.Log;

// Custom a cursor, better group call logs, better performace
public class FastCursor extends AbstractCursor {
	private HashMap<String, ArrayList<Integer>> groupHashMap = new HashMap<String, ArrayList<Integer>>();
	private ArrayList<ArrayList<Integer>> groupList;
	private MatrixCursor mCursor;

	public FastCursor(Cursor cursor) {
		mCursor = new MatrixCursor(cursor.getColumnNames());

		int capacity = cursor.getCount() >> 3;
		if (capacity < 10)
			capacity = 10;
		groupList = new ArrayList<ArrayList<Integer>>(capacity);

		addCursor(cursor);
	}

	// Cursor order by date asc
	public void addCursor(Cursor cursor) {
	
		for (int index = 0; index < cursor.getCount(); index++) {
			cursor.moveToPosition(index);

			Object[] columnValues = new Object[cursor.getColumnCount()];
			columnValues[0] = cursor.getInt(0);
			columnValues[1] = cursor.getString(1);
			columnValues[2] = cursor.getString(2);
			columnValues[3] = cursor.getInt(3);
			columnValues[4] = cursor.getInt(4);
			columnValues[5] = cursor.getLong(5);
			columnValues[6] = cursor.getInt(6);
			columnValues[7] = cursor.getString(7);
			columnValues[8] = cursor.getInt(8);
			columnValues[9] = cursor.getInt(9);

			mCursor.addRow(columnValues);

			String number = cursor.getString(cursor.getColumnIndex(CallLog.Calls.NUMBER));
			ArrayList<Integer> list = groupHashMap.get(number);
			if (list == null) {
				list = new ArrayList<Integer>(4);
				groupHashMap.put(number, list);
			}
			else {
				groupList.remove(list);
			}

			list.add(mCursor.getCount() - 1);
			groupList.add(list);
		}

		// MUST reset mPos, workaroud for AbstractCursor.moveToPosition issue
		mPos = -1;

		Log.d("LOADER", groupHashMap.toString());
		Log.d("LOADER", groupList.toString());
	}

	@Override
	public boolean onMove(int oldPosition, int newPosition) {
		int cursorStartPos = 0;
		int length = groupList.size();
		ArrayList<Integer> list = null;
		for (int i = length - 1; i >= 0; i--) {
			if (newPosition < (cursorStartPos + groupList.get(i).size())) {
				list = groupList.get(i);
				break;
			}

			cursorStartPos += groupList.get(i).size();
		}

		/* Move it to the right position */
		if (list != null) {
			int index = list.size() - (newPosition - cursorStartPos) - 1;
			Boolean ret = mCursor.moveToPosition(list.get(index));
			return ret;
		}
		return false;
	}

	// AbstractCursor implementation.

	@Override
	public void close() {
		super.close();
		
		mCursor.close();
		groupHashMap.clear();
		groupList.clear();
		
		mCursor = null;
		groupHashMap = null;
		groupList = null;
	}

	@Override
	public int getCount() {
		return mCursor.getCount();
	}

	@Override
	public String[] getColumnNames() {
		return mCursor.getColumnNames();
	}

	@Override
	public String getString(int column) {
		return mCursor.getString(column);
	}

	@Override
	public short getShort(int column) {
		return mCursor.getShort(column);
	}

	@Override
	public int getInt(int column) {
		return mCursor.getInt(column);
	}

	@Override
	public long getLong(int column) {
		return mCursor.getLong(column);
	}

	@Override
	public float getFloat(int column) {
		return mCursor.getFloat(column);
	}

	@Override
	public double getDouble(int column) {
		return mCursor.getDouble(column);
	}

	@Override
	public byte[] getBlob(int column) {
		return mCursor.getBlob(column);
	}

	@Override
	public int getType(int column) {
		return mCursor.getType(column);
	}

	@Override
	public boolean isNull(int column) {
		return mCursor.isNull(column);
	}

}

4. 修改CallLogGroupBuilder.java

+++ b/src/org/phoneos/ui/calllog/CallLogGroupBuilder.java
@@ -81,16 +81,17 @@ public class CallLogGroupBuilder {
             final boolean sameNumber = equalNumbers(firstNumber, currentNumber);
             final boolean shouldGroup;

-            if (!sameNumber) {
-                // Should only group with calls from the same number.
-                shouldGroup = false;
-            } else if ( firstCallType == Calls.MISSED_TYPE) {
-                // Voicemail and missed calls should only be grouped with subsequent missed calls.
-                shouldGroup = callType == Calls.MISSED_TYPE;
-            } else {
-                // Incoming and outgoing calls group together.
-                shouldGroup = callType == Calls.INCOMING_TYPE || callType == Calls.OUTGOING_TYPE;
-            }
+            shouldGroup = sameNumber;

转自:http://www.yinqisen.cn/blog-510.html

posted @ 2016-09-08 10:19  鹤骨松姿  阅读(193)  评论(0编辑  收藏  举报