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

org.robolectric.shadows.ShadowContentResolver Maven / Gradle / Ivy

The newest version!
package org.robolectric.shadows;

import android.accounts.Account;
import android.content.ContentProvider;
import android.content.ContentProviderClient;
import android.content.ContentProviderOperation;
import android.content.ContentProviderResult;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.IContentProvider;
import android.content.OperationApplicationException;
import android.content.PeriodicSync;
import android.content.pm.ProviderInfo;
import android.content.res.AssetFileDescriptor;
import android.database.ContentObserver;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.os.CancellationSignal;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
import org.robolectric.annotation.RealObject;
import org.robolectric.annotation.Resetter;
import org.robolectric.fakes.BaseCursor;
import org.robolectric.manifest.AndroidManifest;
import org.robolectric.manifest.ContentProviderData;
import org.robolectric.shadow.api.Shadow;
import org.robolectric.util.NamedStream;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArraySet;

import static org.robolectric.Shadows.shadowOf;

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

  @RealObject ContentResolver realContentResolver;

  private BaseCursor cursor;
  private final List statements = new ArrayList<>();
  private final List insertStatements = new ArrayList<>();
  private final List updateStatements = new ArrayList<>();
  private final List deleteStatements = new ArrayList<>();
  private List notifiedUris = new ArrayList<>();
  private Map uriCursorMap = new HashMap<>();
  private Map inputStreamMap = 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;

  @Resetter
  synchronized 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<>();
  }

  public void registerInputStream(Uri uri, InputStream inputStream) {
    inputStreamMap.put(uri, inputStream);
  }

  @Implementation
  public final InputStream openInputStream(final Uri uri) {
    InputStream inputStream = inputStreamMap.get(uri);
    if (inputStream != null) {
      return inputStream;
    } else {
      return new UnregisteredInputStream(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;
      }
    };
  }

  /**
   * If a {@link ContentProvider} is registered for the given {@link Uri}, its
   * {@link ContentProvider#insert(Uri, ContentValues)} method will be invoked.
   *
   * Tests can verify that this method was called using {@link #getStatements()} or
   * {@link #getInsertStatements()}.
   *
   * If no appropriate {@link ContentProvider} is found, no action will be taken and
   * a {@link Uri} including the incremented value set with {@link #setNextDatabaseIdForInserts(int)} will returned.
   */
  @Implementation
  public final Uri insert(Uri url, ContentValues values) {
    ContentProvider provider = getProvider(url);
    ContentValues valuesCopy = (values == null) ? null : new ContentValues(values);
    InsertStatement insertStatement = new InsertStatement(url, provider, valuesCopy);
    statements.add(insertStatement);
    insertStatements.add(insertStatement);

    if (provider != null) {
      return provider.insert(url, values);
    } else {
      return Uri.parse(url.toString() + "/" + ++nextDatabaseIdForInserts);
    }
  }

  /**
   * If a {@link ContentProvider} is registered for the given {@link Uri}, its
   * {@link ContentProvider#update(Uri, ContentValues, String, String[])} method will be invoked.
   *
   * Tests can verify that this method was called using {@link #getStatements()} or
   * {@link #getUpdateStatements()}.
   *
   * If no appropriate {@link ContentProvider} is found, no action will be taken and
   * the value set with {@link #setNextDatabaseIdForUpdates(int)} will be incremented and returned.
   *
   * *Note:* the return value in this case will be changed to {@code 1} in a future release of Robolectric.
   */
  @Implementation
  public int update(Uri uri, ContentValues values, String where, String[] selectionArgs) {
    ContentProvider provider = getProvider(uri);
    ContentValues valuesCopy = (values == null) ? null : new ContentValues(values);
    UpdateStatement updateStatement = new UpdateStatement(uri, provider, valuesCopy, where, selectionArgs);
    statements.add(updateStatement);
    updateStatements.add(updateStatement);

    if (provider != null) {
      return provider.update(uri, values, where, selectionArgs);
    } else {
      return nextDatabaseIdForUpdates == -1 ? 1 : ++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 {
      BaseCursor returnCursor = getCursor(uri);
      if (returnCursor == null) {
        return null;
      }

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

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

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

  @Implementation
  public String getType(Uri uri) {
    ContentProvider provider = getProvider(uri);
    if (provider != null) {
      return provider.getType(uri);
    } else {
      return null;
    }
  }

  @Implementation
  public Bundle call(Uri uri, String method, String arg, Bundle extras) {
    ContentProvider cp = getProvider(uri);
    if (cp != null) {
      return cp.call(method, arg, extras);
    } else {
      return null;
    }
  }

  @Implementation
  public final ContentProviderClient acquireContentProviderClient(String name) {
    ContentProvider provider = getProvider(name);
    if (provider == null) return null;
    return getContentProviderClient(provider, true);
  }

  @Implementation
  public final ContentProviderClient acquireContentProviderClient(Uri uri) {
    ContentProvider provider = getProvider(uri);
    if (provider == null) return null;
    return getContentProviderClient(provider, true);
  }

  @Implementation
  public final ContentProviderClient acquireUnstableContentProviderClient(String name) {
    ContentProvider provider = getProvider(name);
    if (provider == null) return null;
    return getContentProviderClient(provider, false);
  }

  @Implementation
  public final ContentProviderClient acquireUnstableContentProviderClient(Uri uri) {
    ContentProvider provider = getProvider(uri);
    if (provider == null) return null;
    return getContentProviderClient(provider, false);
  }

  private ContentProviderClient getContentProviderClient(ContentProvider provider, boolean stable) {
    ContentProviderClient client =
        Shadow.newInstance(ContentProviderClient.class,
            new Class[]{ContentResolver.class, IContentProvider.class, boolean.class},
            new Object[]{realContentResolver, provider.getIContentProvider(), stable});
    shadowOf(client).setContentProvider(provider);
    return client;
  }

  @Implementation
  public final IContentProvider acquireProvider(String name) {
    return acquireUnstableProvider(name);
  }

  @Implementation
  public final IContentProvider acquireProvider(Uri uri) {
    return acquireUnstableProvider(uri);
  }

  @Implementation
  public final IContentProvider acquireUnstableProvider(String name) {
    ContentProvider cp = getProvider(name);
    if (cp != null) {
      return cp.getIContentProvider();
    }
    return null;
  }

  @Implementation
  public final IContentProvider acquireUnstableProvider(Uri uri) {
    ContentProvider cp = getProvider(uri);
    if (cp != null) {
      return cp.getIContentProvider();
    }
    return null;
  }

  /**
   * If a {@link ContentProvider} is registered for the given {@link Uri}, its
   * {@link ContentProvider#delete(Uri, String, String[])} method will be invoked.
   *
   * Tests can verify that this method was called using {@link #getDeleteStatements()}
   * or {@link #getDeletedUris()}.
   *
   * If no appropriate {@link ContentProvider} is found, no action will be taken and
   * {@code 1} will be returned.
   */
  @Implementation
  public final int delete(Uri url, String where, String[] selectionArgs) {
    ContentProvider provider = getProvider(url);

    DeleteStatement deleteStatement = new DeleteStatement(url, provider, where, selectionArgs);
    statements.add(deleteStatement);
    deleteStatements.add(deleteStatement);

    if (provider != null) {
      return provider.delete(url, where, selectionArgs);
    } else {
      return 1;
    }
  }

  /**
   * If a {@link ContentProvider} is registered for the given {@link Uri}, its
   * {@link ContentProvider#bulkInsert(Uri, ContentValues[])} method will be invoked.
   *
   * Tests can verify that this method was called using {@link #getStatements()} or
   * {@link #getInsertStatements()}.
   *
   * If no appropriate {@link ContentProvider} is found, no action will be taken and
   * the number of rows in {@code values} will be returned.
   */
  @Implementation
  public final int bulkInsert(Uri url, ContentValues[] values) {
    ContentProvider provider = getProvider(url);

    InsertStatement insertStatement = new InsertStatement(url, provider, values);
    statements.add(insertStatement);
    insertStatements.add(insertStatement);

    if (provider != null) {
      return provider.bulkInsert(url, values);
    } else {
      return values.length;
    }
  }

  /**
   *
   * @param uri
   * @param observer
   * @param syncToNetwork
   */
  @Implementation
  public void notifyChange(Uri uri, ContentObserver observer, boolean syncToNetwork) {
    notifiedUris.add(new NotifiedUri(uri, observer, syncToNetwork));

    CopyOnWriteArraySet observers;
    synchronized (this) {
      observers = contentObservers.get(uri);
    }
    if (observers != null) {
      for (ContentObserver obs : observers) {
        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) throws OperationApplicationException {
    ContentProvider provider = getProvider(authority);
    if (provider != null) {
      return provider.applyBatch(operations);
    } else {
      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 cancelSync(Account account, String authority) {
    Status status = getStatus(account, authority);
    if (status != null) {
      status.syncRequests = 0;
      if (status.syncExtras != null) {
        status.syncExtras.clear();
      }
      // This may be too much, as the above should be sufficient.
      if (status.syncs != null) {
        status.syncs.clear();
      }
    }
  }

  @Implementation
  public static boolean isSyncActive(Account account, String authority) {
    ShadowContentResolver.Status status = getStatus(account, authority);
    // TODO: this means a sync is *perpetually* active after one request
    return status != null && status.syncRequests > 0;
  }

  @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);
    removePeriodicSync(account, authority, 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) {
      for (int i = 0; i < status.syncs.size(); ++i) {
        if (isBundleEqual(extras, status.syncs.get(i).extras)) {
          status.syncs.remove(i);
          break;
        }
      }
    }
  }

  @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 || !ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {
      return null;
    }
    return getProvider(uri.getAuthority());
  }

  synchronized private static ContentProvider getProvider(String authority) {
    if (!providers.containsKey(authority)) {
      AndroidManifest manifest = shadowOf(RuntimeEnvironment.application).getAppManifest();
      if (manifest != null) {
        for (ContentProviderData providerData : manifest.getContentProviders()) {
          // todo: handle multiple authorities
          if (providerData.getAuthorities().equals(authority)) {
            providers.put(providerData.getAuthorities(), createAndInitialize(providerData));
          }
        }
      }
    }
    return providers.get(authority);
  }

  /**
   * Internal-only method, do not use!
   *
   * Instead, use
   * ```java
   * ProviderInfo info = new ProviderInfo();
   * info.authority = authority;
   * Robolectric.buildContentProvider(ContentProvider.class).create(info);
   * ```
   */
  synchronized public static void registerProviderInternal(String authority, ContentProvider provider) {
    providers.put(authority, provider);
  }

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

  /**
   * Retrieve information on the status of the given account.
   *
   * @param account the account
   * @param authority the authority
   * @param create whether to create if no such account is found
   * @return the account's status
   */
  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(BaseCursor cursor) {
    this.cursor = cursor;
  }

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

  @SuppressWarnings({"unused", "WeakerAccess"})
  public void setNextDatabaseIdForInserts(int nextId) {
    nextDatabaseIdForInserts = nextId;
  }

  /**
   * Set the value to be returned by {@link ContentResolver#update(Uri, ContentValues, String, String[])}
   * when no appropriate {@link ContentProvider} can be found.
   *
   * @deprecated This method will be removed in Robolectric 3.5. Instead, {@code 1} will be returned.
   *
   * @param nextId the number of rows to return
   */
  @Deprecated
  @SuppressWarnings({"unused", "WeakerAccess"})
  public void setNextDatabaseIdForUpdates(int nextId) {
    nextDatabaseIdForUpdates = nextId;
  }

  /**
   * Returns the list of {@link InsertStatement}s, {@link UpdateStatement}s, and
   * {@link DeleteStatement}s invoked on this {@link ContentResolver}.
   *
   * @return a list of statements
   */
  @SuppressWarnings({"unused", "WeakerAccess"})
  public List getStatements() {
    return statements;
  }

  /**
   * Returns the list of {@link InsertStatement}s for corresponding calls to
   * {@link ContentResolver#insert(Uri, ContentValues)} or
   * {@link ContentResolver#bulkInsert(Uri, ContentValues[])}.
   *
   * @return a list of insert statements
   */
  @SuppressWarnings({"unused", "WeakerAccess"})
  public List getInsertStatements() {
    return insertStatements;
  }

  /**
   * Returns the list of {@link UpdateStatement}s for corresponding calls to
   * {@link ContentResolver#update(Uri, ContentValues, String, String[])}.
   *
   * @return a list of update statements
   */
  @SuppressWarnings({"unused", "WeakerAccess"})
  public List getUpdateStatements() {
    return updateStatements;
  }

  @SuppressWarnings({"unused", "WeakerAccess"})
  public List getDeletedUris() {
    List uris = new ArrayList<>();
    for (DeleteStatement deleteStatement : deleteStatements) {
      uris.add(deleteStatement.getUri());
    }
    return uris;
  }

  /**
   * Returns the list of {@link DeleteStatement}s for corresponding calls to
   * {@link ContentResolver#delete(Uri, String, String[])}.
   *
   * @return a list of delete statements
   */
  @SuppressWarnings({"unused", "WeakerAccess"})
  public List getDeleteStatements() {
    return deleteStatements;
  }

  @SuppressWarnings({"unused", "WeakerAccess"})
  public List getNotifiedUris() {
    return notifiedUris;
  }

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

  public void setContentProviderResult(ContentProviderResult[] contentProviderResults) {
    this.contentProviderResults = contentProviderResults;
  }

  @Implementation
  synchronized public void registerContentObserver( Uri uri, boolean notifyForDescendents, ContentObserver observer) {
    CopyOnWriteArraySet observers = contentObservers.get(uri);
    if (observers == null) {
      observers = new CopyOnWriteArraySet<>();
      contentObservers.put(uri, observers);
    }
    observers.add(observer);
  }

  @Implementation
  public void registerContentObserver(Uri uri, boolean notifyForDescendents, ContentObserver observer, int userHandle) {
    registerContentObserver(uri, notifyForDescendents, observer);
  }

  @Implementation
  public void unregisterContentObserver( ContentObserver observer ) {
    if ( observer != null ) {
      Collection> observerSets;
      synchronized (this) {
        observerSets = contentObservers.values();
      }
      for (CopyOnWriteArraySet observers : observerSets) {
        observers.remove(observer);
      }
    }
  }

  /**
   * Clears the list of registered {@link ContentObserver}s.
   *
   * Since a new {@link ContentResolver} is created for each test case,
   * this method generally need not be called explicitly.
   */
  @SuppressWarnings({"unused", "WeakerAccess"})
  synchronized public void clearContentObservers() {
    contentObservers.clear();
  }

  /**
   * Returns the content observers registered with the given URI.
   *
   * Will be empty if no observer is registered.
   *
   * @param uri Given URI
   * @return The content observers, or null.
   */
  synchronized public Collection getContentObservers( Uri uri ) {
    CopyOnWriteArraySet observers = contentObservers.get(uri);
    return (observers == null) ? Collections.emptyList() : observers;
  }

  @Implementation
  public final AssetFileDescriptor openTypedAssetFileDescriptor(Uri uri, String mimeType, Bundle opts) throws FileNotFoundException {
    ContentProvider provider = getProvider(uri);
    if (provider == null) {
      return null;
    }
    return provider.openTypedAssetFile(uri, mimeType, opts);
  }

  private static ContentProvider createAndInitialize(ContentProviderData providerData) {
    try {
      ContentProvider provider = (ContentProvider) Class.forName(providerData.getClassName()).newInstance();
      initialize(provider, providerData.getAuthorities());
      return provider;
    } catch (InstantiationException | ClassNotFoundException | IllegalAccessException e) {
      throw new RuntimeException("Error instantiating class " + providerData.getClassName());
    }
  }

  private static void initialize(ContentProvider provider, String authorities) {
    ProviderInfo providerInfo = new ProviderInfo();
    providerInfo.authority = authorities; // todo: support multiple authorities
    providerInfo.grantUriPermissions = true;
    provider.attachInfo(RuntimeEnvironment.application, providerInfo);
    provider.onCreate();
  }

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

  private static boolean isBundleEqual(Bundle bundle1, Bundle bundle2) {
    if (bundle1 == null || bundle2 == null) {
      return false;
    }
    if (bundle1.size() != bundle2.size()) {
      return false;
    }
    for (String key : bundle1.keySet()) {
      if (!bundle1.get(key).equals(bundle2.get(key))) {
        return false;
      }
    }
    return true;
  }

  public static class Statement {
    private final Uri uri;
    private final ContentProvider contentProvider;

    Statement(Uri uri, ContentProvider contentProvider) {
      this.uri = uri;
      this.contentProvider = contentProvider;
    }

    public Uri getUri() {
      return uri;
    }

    @SuppressWarnings({"unused", "WeakerAccess"})
    public ContentProvider getContentProvider() {
      return contentProvider;
    }
  }

  public static class InsertStatement extends Statement {
    private final ContentValues[] bulkContentValues;

    InsertStatement(Uri uri, ContentProvider contentProvider, ContentValues contentValues) {
      super(uri, contentProvider);
      this.bulkContentValues = new ContentValues[]{contentValues};
    }

    InsertStatement(Uri uri, ContentProvider contentProvider, ContentValues[] bulkContentValues) {
      super(uri, contentProvider);
      this.bulkContentValues = bulkContentValues;
    }

    @SuppressWarnings({"unused", "WeakerAccess"})
    public ContentValues getContentValues() {
      if (bulkContentValues.length != 1) {
        throw new ArrayIndexOutOfBoundsException("bulk insert, use getBulkContentValues() instead");
      }
      return bulkContentValues[0];
    }

    @SuppressWarnings({"unused", "WeakerAccess"})
    public ContentValues[] getBulkContentValues() {
      return bulkContentValues;
    }
  }

  public static class UpdateStatement extends Statement {
    private final ContentValues values;
    private final String where;
    private final String[] selectionArgs;

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

    @SuppressWarnings({"unused", "WeakerAccess"})
    public ContentValues getContentValues() {
      return values;
    }

    @SuppressWarnings({"unused", "WeakerAccess"})
    public String getWhere() {
      return where;
    }

    @SuppressWarnings({"unused", "WeakerAccess"})
    public String[] getSelectionArgs() {
      return selectionArgs;
    }
  }

  public static class DeleteStatement extends Statement {
    private final String where;
    private final String[] selectionArgs;

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

    @SuppressWarnings({"unused", "WeakerAccess"})
    public String getWhere() {
      return where;
    }

    @SuppressWarnings({"unused", "WeakerAccess"})
    public String[] getSelectionArgs() {
      return selectionArgs;
    }
  }

  private static class UnregisteredInputStream extends InputStream implements NamedStream {
    private final Uri uri;

    UnregisteredInputStream(Uri uri) {
      this.uri = uri;
    }

    @Override
    public int read() throws IOException {
      throw new UnsupportedOperationException("You must use ShadowContentResolver.registerInputStream() in order to call read()");
    }

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




© 2015 - 2025 Weber Informatics LLC | Privacy Policy