All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.xtremelabs.robolectric.shadows.ShadowContentResolver Maven / Gradle / Ivy

The newest version!
package com.xtremelabs.robolectric.shadows;

import android.accounts.Account;
import android.content.*;
import android.database.ContentObserver;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import com.xtremelabs.robolectric.internal.Implementation;
import com.xtremelabs.robolectric.internal.Implements;
import com.xtremelabs.robolectric.tester.android.database.TestCursor;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.*;
import java.util.Map.Entry;

@Implements(ContentResolver.class)
public class ShadowContentResolver {
    private int nextDatabaseIdForInserts;
    private int nextDatabaseIdForUpdates;

    private TestCursor cursor;
    private final List insertStatements = new ArrayList();
    private final List updateStatements = new ArrayList();
    private final List deleteStatements = new ArrayList();
    private List notifiedUris = new ArrayList();
    private HashMap uriCursorMap = new HashMap();
    private final Map> contentProviderOperations = new HashMap>();
    private ContentProviderResult[] contentProviderResults;

    private final Map contentObservers = new HashMap();
    
    private static final Map>  syncableAccounts =
            new HashMap>();
    private static final Map providers = new HashMap();
    private static boolean masterSyncAutomatically;
    
    public static void reset() {
        syncableAccounts.clear();
        providers.clear();
        masterSyncAutomatically = false;
    }

    public static class NotifiedUri {
        public final Uri uri;
        public final boolean syncToNetwork;
        public final ContentObserver observer;

        public NotifiedUri(Uri uri, ContentObserver observer, boolean syncToNetwork) {
            this.uri = uri;
            this.syncToNetwork = syncToNetwork;
            this.observer = observer;
        }
    }

    public static class Status {
        public int syncRequests;
        public int state = -1;
        public boolean syncAutomatically;
        public Bundle syncExtras;
        public List syncs = new ArrayList();
    }

    @Implementation
    public final InputStream openInputStream(final Uri uri) {
        return new InputStream() {
            @Override
            public int read() throws IOException {
                throw new UnsupportedOperationException();
            }

            @Override
            public String toString() {
                return "stream for " + uri;
            }
        };
    }
    
    @Implementation
    public final OutputStream openOutputStream(final Uri uri) {
        return new OutputStream() {
            
            @Override
            public void write(int arg0) throws IOException {                
            }

            @Override
            public String toString() {
                return "outputstream for " + uri;
            }
        };
    }

    @Implementation
    public final Uri insert(Uri url, ContentValues values) {
        ContentProvider provider = getProvider(url);
        if (provider != null) {
            return provider.insert(url, values);
        } else {
            InsertStatement insertStatement = new InsertStatement(url, new ContentValues(values));
            insertStatements.add(insertStatement);
            return Uri.parse(url.toString() + "/" + nextDatabaseIdForInserts++);
        }
    }

    @Implementation
    public int update(Uri uri, ContentValues values, String where, String[] selectionArgs) {
        ContentProvider provider = getProvider(uri);
        if (provider != null) {
            return provider.update(uri, values, where, selectionArgs);
        } else {
            UpdateStatement updateStatement = new UpdateStatement(uri, new ContentValues(values), where, selectionArgs);
            updateStatements.add(updateStatement);
            return nextDatabaseIdForUpdates++;
        }
    }

    @Implementation
    public final Cursor query(Uri uri, String[] projection, String selection,
            String[] selectionArgs, String sortOrder) {
        ContentProvider provider = getProvider(uri);
        if (provider != null) {
            return provider.query(uri, projection, selection, selectionArgs, sortOrder);
        } else {
            TestCursor returnCursor = getCursor(uri);
            if (returnCursor == null) {
                return null;
            }

            returnCursor.setQuery(uri, projection, selection, selectionArgs,
                    sortOrder);
            return returnCursor;
        }
    }

    @Implementation
    public final int delete(Uri url, String where, String[] selectionArgs) {
        ContentProvider provider = getProvider(url);
        if (provider != null) {
            return provider.delete(url, where, selectionArgs);
        } else {
            DeleteStatement deleteStatement = new DeleteStatement(url, where, selectionArgs);
            deleteStatements.add(deleteStatement);
            return 1;
        }
    }

    @Implementation
    public final int bulkInsert(Uri url, ContentValues[] values) {
        ContentProvider provider = getProvider(url);
        if (provider != null) {
            return provider.bulkInsert(url, values);
        } else {
            return 0;
        }
    }

    @Implementation
    public void notifyChange(Uri uri, ContentObserver observer, boolean syncToNetwork) {
        notifiedUris.add(new NotifiedUri(uri, observer, syncToNetwork));
        
        // TODO does not support multiple observers for a URI
        ContentObserver obs = contentObservers.get(uri);
        if ( obs != null && obs != observer  ) {
        	obs.dispatchChange( false, uri );
        }
    	if ( observer != null && observer.deliverSelfNotifications() ) {
    		observer.dispatchChange( true, uri );
    	}
    }

    @Implementation
    public void notifyChange(Uri uri, ContentObserver observer) {
        notifyChange(uri, observer, false);
    }

    @Implementation
    public ContentProviderResult[] applyBatch(String authority, ArrayList operations) {
        contentProviderOperations.put(authority, operations);
        return contentProviderResults;
    }

    @Implementation
    public static void requestSync(Account account, String authority, Bundle extras) {
        validateSyncExtrasBundle(extras);
        Status status = getStatus(account, authority, true);
        status.syncRequests++;
        status.syncExtras = extras;
    }

    @Implementation
    public static void setIsSyncable(Account account, String authority, int syncable) {
        getStatus(account, authority, true).state = syncable;
    }

    @Implementation
    public static int getIsSyncable(Account account, String authority) {
        return getStatus(account, authority, true).state;
    }

    @Implementation
    public static boolean getSyncAutomatically(Account account, String authority) {
        return getStatus(account, authority, true).syncAutomatically;
    }

    @Implementation
    public static void setSyncAutomatically(Account account, String authority, boolean sync) {
        getStatus(account, authority, true).syncAutomatically = sync;
    }

    @Implementation
    public static void addPeriodicSync(Account account, String authority, Bundle extras,
                                       long pollFrequency) {

        validateSyncExtrasBundle(extras);
        getStatus(account, authority, true).syncs.add(new PeriodicSync(account, authority, extras, pollFrequency));
    }

    @Implementation
    public static void removePeriodicSync(Account account, String authority, Bundle extras) {
        validateSyncExtrasBundle(extras);
        Status status = getStatus(account, authority);
        if (status != null) status.syncs.clear();
    }

    @Implementation
    public static List getPeriodicSyncs(Account account, String authority) {
        return getStatus(account, authority, true).syncs;
    }

    @Implementation
    public static void validateSyncExtrasBundle(Bundle extras) {
        for (String key : extras.keySet()) {
            Object value = extras.get(key);
            if (value == null) continue;
            if (value instanceof Long) continue;
            if (value instanceof Integer) continue;
            if (value instanceof Boolean) continue;
            if (value instanceof Float) continue;
            if (value instanceof Double) continue;
            if (value instanceof String) continue;
            if (value instanceof Account) continue;
            throw new IllegalArgumentException("unexpected value type: "
                    + value.getClass().getName());
        }
    }

    @Implementation
    public static void setMasterSyncAutomatically(boolean sync) {
        masterSyncAutomatically = sync;

    }

    @Implementation
    public static boolean getMasterSyncAutomatically() {
        return masterSyncAutomatically;
    }


    public static ContentProvider getProvider(Uri uri) {
        if (uri == null) {
            return null;
        } else if (!ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {
            return null;
        } else {
            return providers.get(uri.getAuthority());
        }
    }

    public static void registerProvider(String authority, ContentProvider provider) {
        providers.put(authority, provider);
    }

    public static Status getStatus(Account account, String authority) {
        return getStatus(account, authority, false);
    }

    public static Status getStatus(Account account, String authority, boolean create) {
        Map map = syncableAccounts.get(authority);
        if (map == null) {
            map = new HashMap();
            syncableAccounts.put(authority, map);
        }
        Status status = map.get(account);
        if (status == null && create) {
            status = new Status();
            map.put(account, status);
        }
        return status;
    }

    public void setCursor(TestCursor cursor) {
        this.cursor = cursor;
    }

    public void setCursor(Uri uri, TestCursor cursorForUri) {
        this.uriCursorMap.put(uri, cursorForUri);
    }

    public void setNextDatabaseIdForInserts(int nextId) {
        nextDatabaseIdForInserts = nextId;
    }

    public void setNextDatabaseIdForUpdates(int nextId) {
        nextDatabaseIdForUpdates = nextId;
    }

    public List getInsertStatements() {
        return insertStatements;
    }

    public List getUpdateStatements() {
        return updateStatements;
    }

    public List getDeletedUris() {
        List uris = new ArrayList();
        for (DeleteStatement deleteStatement : deleteStatements) {
            uris.add(deleteStatement.getUri());
        }
        return uris;
    }

    public List getDeleteStatements() {
        return deleteStatements;
    }

    public List getNotifiedUris() {
        return notifiedUris;
    }

    public ArrayList getContentProviderOperations(String authority) {
        ArrayList operations = contentProviderOperations.get(authority);
        if (operations == null)
            return new ArrayList();
        return operations;
    }

    public void setContentProviderResult(ContentProviderResult[] contentProviderResults) {
        this.contentProviderResults = contentProviderResults;
    }
    
    @Implementation
    public void registerContentObserver( Uri uri, boolean notifyForDescendents, ContentObserver observer) {
        // TODO does not support multiple observers for a URI
    	contentObservers.put( uri, observer );
    }
    
    @Implementation
    public void unregisterContentObserver( ContentObserver observer ) {
    	if ( observer != null && contentObservers.containsValue( observer ) ) {
    		Set> entries = contentObservers.entrySet();
    		for ( Entry e : entries ) {
    			ContentObserver other = e.getValue();
    			if ( observer == other || observer.equals(other) ) {
    	        	contentObservers.remove( e.getKey() );
    	        	return;
    			}
    		}
    	}
    }
    
    /**
     * Non-Android accessor.  Clears the list of registered content observers.
     * Commonly used in test case setup.
     */
    public void clearContentObservers() {
    	contentObservers.clear();
    }
    
    /**
     * Non-Android accessor.  Returns the content observer registered with
     * the given URI, or null if none registered.
     * @param uri
     * @return
     */
    public ContentObserver getContentObserver( Uri uri ) {
    	return contentObservers.get(uri);
    }

    private TestCursor getCursor(Uri uri) {
        if (uriCursorMap.get(uri) != null) {
            return uriCursorMap.get(uri);
        } else if (cursor != null) {
            return cursor;
        } else {
            return null;
        }
    }

    public static class InsertStatement {
        private final Uri uri;
        private final ContentValues contentValues;

        public InsertStatement(Uri uri, ContentValues contentValues) {
            this.uri = uri;
            this.contentValues = contentValues;
        }

        public Uri getUri() {
            return uri;
        }

        public ContentValues getContentValues() {
            return contentValues;
        }
    }

    public static class UpdateStatement {
        private final Uri uri;
        private final ContentValues values;
        private final String where;
        private final String[] selectionArgs;

        public UpdateStatement(Uri uri, ContentValues values, String where, String[] selectionArgs) {
            this.uri = uri;
            this.values = values;
            this.where = where;
            this.selectionArgs = selectionArgs;
        }

        public Uri getUri() {
            return uri;
        }

        public ContentValues getContentValues() {
            return values;
        }

        public String getWhere() {
            return where;
        }

        public String[] getSelectionArgs() {
            return selectionArgs;
        }
    }

    public static class DeleteStatement {
        private final Uri uri;
        private final String where;
        private final String[] selectionArgs;

        public DeleteStatement(Uri uri, String where, String[] selectionArgs) {
            this.uri = uri;
            this.where = where;
            this.selectionArgs = selectionArgs;
        }

        public Uri getUri() {
            return uri;
        }

        public String getWhere() {
            return where;
        }

        public String[] getSelectionArgs() {
            return selectionArgs;
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy