Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cursor wrapping/unwrapping in ContentProvider

I'm creating ContentProvider which is a proxy of another ContentProvider (for security issues and to give access to part of functionality of full app).

public class GFContactsProvider extends ContactsProvider implements
      DatabaseConstants {
    private Context mContext;
    private ContentResolver mContentResolver;
    @Override
     public boolean onCreate() {
      mContext = getContext();
      mContentResolver = mContext.getContentResolver();


     }
    @Override
     public Cursor query(Uri uri, String[] projection, String selection,
       String[] selectionArgs, String sortOrder) {

     Cursor result = mContentResolver.query(ContactsContract.getContactsURI(Long.parseLong(address.get(1))), null, null, null, ContactsContract.ContactColumns.SHOW_NAME);  
return result;
     }
    }

After calling inner CP from my CP I recive unexpected exception:

java.lang.UnsupportedOperationException: Only CrossProcessCursor cursors are supported across process for now

The exception concerns the wrapping of the Cursor by the CP and transfer it wrapped, Outer CP can't wrap it again so I have a problem here. When I checked class of returned cursor I received CursorWrapperInner.

Is there any way to unwrap cursor (from this CWI to regular Cursor) in my outer CP (but not by transfering all data to MatrixCursor in loop – it's too time-consuming).

like image 587
ViviQ Avatar asked Oct 20 '10 09:10

ViviQ


1 Answers

There's no need to "unwrap" the cursor. The problem is, if your content provider is providing results to a client that runs in another process, the Cursor you returned from query() must implement CrossProcessCursor interface. It's not stated in document (AFAICS), but you can see this from your log.

All you need to do is implement CrossProcessCursor interface, and wrap it around your cursor.

// your query statement does not seem right..BTW
Cursor result = mContentResolver.query(...); 
// now, you return a CrossProcessCursorWrapper.
return new CrossProcessCursorWrapper(result);

Implementation of CrossProcessCursor methods are ported from AbstractCursor. Some slight modifications are made so the compiler's happy:

public class CrossProcessCursorWrapper extends CursorWrapper implements
        CrossProcessCursor {
    public CrossProcessCursorWrapper(Cursor cursor) {
        super(cursor);
    }

    @Override
    public CursorWindow getWindow() {
        return null;
    }

    @Override
    public void fillWindow(int position, CursorWindow window) {
        if (position < 0 || position > getCount()) {
            return;
        }
        window.acquireReference();
        try {
            moveToPosition(position - 1);
            window.clear();
            window.setStartPosition(position);
            int columnNum = getColumnCount();
            window.setNumColumns(columnNum);
            while (moveToNext() && window.allocRow()) {
                for (int i = 0; i < columnNum; i++) {
                    String field = getString(i);
                    if (field != null) {
                        if (!window.putString(field, getPosition(), i)) {
                            window.freeLastRow();
                            break;
                        }
                    } else {
                        if (!window.putNull(getPosition(), i)) {
                            window.freeLastRow();
                            break;
                        }
                    }
                }
            }
        } catch (IllegalStateException e) {
            // simply ignore it
        } finally {
            window.releaseReference();
        }
    }

    @Override
    public boolean onMove(int oldPosition, int newPosition) {
        return true;
    }
}
like image 155
DenMark Avatar answered Sep 20 '22 03:09

DenMark