Unable to open content: Custom Content Provider - android

I have two app, from another app I want to get all images,
suppose there is StickerProvider and MainActivity different app
StickerProvider is ContentProvider, MainActivity has ContentResolver
StickerProvider App has Asset Folder
Asset----> Stickers ----------> a.png, b.png
public class StickerProvider extends ContentProvider {
private final static String LOG_TAG = StickerProvider.class.getName();
private static final String[] COLUMNS = {
OpenableColumns.DISPLAY_NAME, OpenableColumns.SIZE};
#Override
public boolean onCreate() {
return true;
}
#Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
/**
* Source: {#link FileProvider#query(Uri, String[], String, String[], String)} .
*/
if (projection == null) {
projection = COLUMNS;
}
String[] images = new String[0];
try {
images = getContext().getAssets().list("stickers");
ArrayList<String> listImages = new ArrayList<String>(Arrays.asList(images));
final MatrixCursor cursor = new MatrixCursor(new String[]{"path"}, 1);
for (int i = 0; i < listImages.size(); i++) {
cursor.addRow(new String[]{listImages.get(i)});
}
return cursor;
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
#Override
public String getType(Uri uri) {
/**
* Source: {#link FileProvider#getType(Uri)} .
*/
final String file_name = uri.getLastPathSegment();
final int lastDot = file_name.lastIndexOf('.');
if (lastDot >= 0) {
final String extension = file_name.substring(lastDot + 1);
final String mime = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
if (mime != null) {
return mime;
}
}
return "image/png";
}
#Override
public Uri insert(Uri uri, ContentValues values) {
return null;
}
#Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
return 0;
}
#Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
return 0;
}
}
It's menifest file is
<provider
android:name="com.example.StickerProvider"
android:authorities="com.example"
android:exported="true"
android:grantUriPermissions="true"
android:label="StickerProvider" />
Another app is MainActivity ------> From this I want to fetch all images of above apps
public class MainActivity extends AppCompatActivity {
int i=0;
private static final String TAG = "MainActivity";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ImageView ivOne = (ImageView)findViewById(R.id.ivOne);
ImageView ivTwo = (ImageView)findViewById(R.id.ivTwo);
try {
ContentResolver resolver = getContentResolver();
Cursor cursor =
resolver.query(Uri.parse("content://com.example/stickers"),
null,
null,
null,
null);
if (cursor.moveToFirst()) {
do {
String word = cursor.getString(0);
if(i==0){
ivOne.setImageURI(Uri.parse("content://com.example/stickers/"+word));
}else if(i==1){
ivTwo.setImageURI(Uri.parse("content://com.example/stickers/"+word));
}
// do something meaningful
Log.d(TAG, "onCreate: "+word);
} while (cursor.moveToNext());
}
}catch(Exception e){
e.printStackTrace();
}
}
}
When ever I start MainActivity App I am getting below exception
Unable to open content: content://com.example/a.png
java.io.FileNotFoundException: No files supported by provider at content://com.example/a.png
at android.database.DatabaseUtils.readExceptionWithFileNotFoundExceptionFromParcel(DatabaseUtils.java:144)
at android.content.ContentProviderProxy.openTypedAssetFile(ContentProviderNative.java:692)
at android.content.ContentResolver.openTypedAssetFileDescriptor(ContentResolver.java:1149)
at android.content.ContentResolver.openAssetFileDescriptor(ContentResolver.java:986)
at android.content.ContentResolver.openInputStream(ContentResolver.java:706)
at android.widget.ImageView.getDrawableFromUri(ImageView.java:900)
at android.widget.ImageView.resolveUri(ImageView.java:871)
at android.widget.ImageView.setImageURI(ImageView.java:490)
at android.support.v7.widget.AppCompatImageView.setImageURI(AppCompatImageView.java:124)
at com.pixr.photo.collage.MainActivity.onCreate(MainActivity.java:36)
at android.app.Activity.performCreate(Activity.java:6684)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1119)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2652)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2766)
at android.app.ActivityThread.-wrap12(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1507)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6236)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:891)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:781)

ivOne.setImageURI(Uri.parse("content://com.example/stickers/"+word));
Your ContentProvider does not support this. It does not implement openFile() or any of its variants.
Either:
Use an existing ContentProvider that offers support for serving assets, such as my StreamProvider, or
Augment your provider to support openFile(), such as I do in this sample app

ic_launcher is related with app icon. There is no app icon. Check your icon in your drawable directory.

Related

How to combine multiple Uri from Images

I have this function that queries the gallery images
public void getImagesFromGallary(Context context) {
List<Uri> imagesUri = new ArrayList<>();
List<Uri> imageOrientationUri = new ArrayList<>();
Cursor imageCursor = null;
try {
final String[] columns = {MediaStore.Images.Media.DATA, MediaStore.Images.ImageColumns.ORIENTATION};
final String orderBy = MediaStore.Images.Media.DATE_ADDED + " DESC";
imageCursor = context.getApplicationContext().getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, columns, null, null, orderBy);
while (imageCursor.moveToNext()) {
Uri uri = Uri.parse(imageCursor.getString(imageCursor.getColumnIndex(MediaStore.Images.Media.DATA)));
Uri uriOrientation = Uri.parse(imageCursor.getString(imageCursor.getColumnIndex(MediaStore.Images.Media.ORIENTATION)));
imagesUri.add(uri);
imageOrientationUri.add(uriOrientation);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (imageCursor != null && !imageCursor.isClosed()) {
imageCursor.close();
}
}
}
Do I have to have two Uri list for this, for instance I have a
imagesUri list and a imageOrientationUri list.
What if I want more information from the Image do I have to parse another Uri from the cursor?
You can create an object for the image like:
public class ImageDetails {
private URI imageURI;
private URI imageOrientationURI;
public URI getImageURI() {
return imageURI;
}
public void setImageURI(URI imageURI) {
this.imageURI = imageURI;
}
public URI getImageOrientationURI() {
return imageOrientationURI;
}
public void setImageOrientationURI(URI imageOrientationURI) {
this.imageOrientationURI = imageOrientationURI;
}
}
And you create a single list and add details to it like:
public void getImagesFromGallary(Context context) {
List<ImageDetails> imageDetails = new ArrayList<>();
Cursor imageCursor = null;
try {
final String[] columns = {MediaStore.Images.Media.DATA, MediaStore.Images.ImageColumns.ORIENTATION};
final String orderBy = MediaStore.Images.Media.DATE_ADDED + " DESC";
imageCursor = context.getApplicationContext().getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, columns, null, null, orderBy);
while (imageCursor.moveToNext()) {
ImageDetails tmp = new ImageDetails();
tmp.setImageURI(Uri.parse(imageCursor.getString(imageCursor.getColumnIndex(MediaStore.Images.Media.ORIENTATION))));
tmp.setImageOrientationURI(Uri.parse(imageCursor.getString(imageCursor.getColumnIndex(MediaStore.Images.Media.DATA))));
imageDetails.add(tmp);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (imageCursor != null && !imageCursor.isClosed()) {
imageCursor.close();
}
}
So for each new property now, you can create a new variable in the class along with the getters and setters

Android DBFlow and CursorLoader

Anyone knows how to use cursorLoader with DBFlow ? I seen this issue but this is not added to DBFlow.
Thanks.
You can find official docs here or you can implement it the way i have
DBFlow ver used 3
//I have edited my answer & provided easier way for content provider part below
add this to manifest inside application
<provider
android:authorities="com.hashx19.pristinekashmir.mycontentprovider"
android:exported="false"
android:name=".MyContentProvider"/>
Create java file named MyContentProvider & copy below code in it
& replace AUTHORITY ,ENDPOINT, AppDatabase(Your database name) ,TableClassName as per you project.
import android.content.ContentProvider;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.CursorIndexOutOfBoundsException;
import android.net.Uri;
import com.hashx19.pristinekashmir.MySQLiteHelper;
import com.raizlabs.android.dbflow.annotation.ConflictAction;
import com.raizlabs.android.dbflow.config.FlowManager;
import com.raizlabs.android.dbflow.structure.ModelAdapter;
import java.util.Arrays;
import java.util.HashSet;
/**
* Created by Filu on 8/25/2016.
*/
public class MyContentProvider extends ContentProvider {
public static final String AUTHORITY = "com.hashx19.pristinekashmir.mycontentprovider";
private static final String ENDPOOINT = "feeds";
// #ContentUri(path = ENDPOOINT, type = ContentUri.ContentType.VND_MULTIPLE + ENDPOOINT)
public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY
+ "/" + ENDPOOINT);
private static final int feeds_CONTENT_URI = 0;
private static final UriMatcher MATCHER = new UriMatcher(UriMatcher.NO_MATCH);
static {
MATCHER.addURI(AUTHORITY, ENDPOOINT, feeds_CONTENT_URI);
}
;
#Override
public final String getType(Uri uri) {
String type = null;
switch(MATCHER.match(uri)) {
case feeds_CONTENT_URI: {
type = "vnd.android.cursor.dir/" +ENDPOINT;
break;
}
default: {
throw new IllegalArgumentException("Unknown URI" + uri);
}
}
return type;
}
#Override
public boolean onCreate() {
return false;
}
#Override
public final Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
android.database.Cursor cursor = null;
switch(MATCHER.match(uri)) {
case feeds_CONTENT_URI: {
cursor = FlowManager.getDatabase("AppDatabase").getWritableDatabase().query("TableClassName", projection, selection, selectionArgs, null, null, sortOrder);
break;
}
}
if (cursor != null) {
cursor.setNotificationUri(getContext().getContentResolver(), uri);
}
return cursor;
}
#Override
public final Uri insert(Uri uri, ContentValues values) {
switch(MATCHER.match(uri)) {
case feeds_CONTENT_URI: {
ModelAdapter adapter = FlowManager.getModelAdapter(FlowManager.getTableClassForName("AppDatabase", "TableClassName"));
final long id = FlowManager.getDatabase("AppDatabase").getWritableDatabase().insertWithOnConflict("TableClassName", null, values, ConflictAction.getSQLiteDatabaseAlgorithmInt(adapter.getInsertOnConflictAction()));
getContext().getContentResolver().notifyChange(uri, null);
return ContentUris.withAppendedId(uri, id);
}
default: {
throw new IllegalStateException("Unknown Uri" + uri);
}
}
}
#Override
public final int delete(Uri uri, String selection, String[] selectionArgs) {
switch(MATCHER.match(uri)) {
case feeds_CONTENT_URI: {
long count = FlowManager.getDatabase("AppDatabase").getWritableDatabase().delete("TableClassName", selection, selectionArgs);
if (count > 0) {
getContext().getContentResolver().notifyChange(uri, null);
}
return (int) count;
}
default: {
throw new IllegalArgumentException("Unknown URI" + uri);
}
}
}
#Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
switch(MATCHER.match(uri)) {
case feeds_CONTENT_URI: {
ModelAdapter adapter = FlowManager.getModelAdapter(FlowManager.getTableClassForName("AppDatabase", "TableClassName"));
long count = FlowManager.getDatabase("AppDatabase").getWritableDatabase().updateWithOnConflict("TableClassName", values, selection, selectionArgs, ConflictAction.getSQLiteDatabaseAlgorithmInt(adapter.getUpdateOnConflictAction()));
if (count > 0) {
getContext().getContentResolver().notifyChange(uri, null);
}
return (int) count;
}
default: {
throw new IllegalStateException("Unknown Uri" + uri);
}
}
}
}
then when overriding Loader methods do something like this
getLoaderManager().initLoader(1, null, this);
#Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
String selection, sortOrder;
String[] selectionArgs, projection;
selection = ...;
selectionArgs = ...;
sortOrder = ...;
projection= new String[]{"id","date", "link","title","content","excerpt","author",};
CursorLoader cursorLoader = new CursorLoader(getContext(),MyContentProvider.CONTENT_URI, projection,null,null,null);
return cursorLoader;
}
#Override
public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
TableClass post = new TableClass();
while (!cursor.isAfterLast()) {
try{
post.setId(cursor.getInt(cursor.getColumnIndex("id")));
}catch (NullPointerException e){
e.printStackTrace();
}catch (CursorIndexOutOfBoundsException c){
c.printStackTrace();
}
}
}
#Override
public void onLoaderReset(Loader<Cursor> loader) {
}
editted
Figured out easier way to implement content provider .
add this to your manifest / or modify this way if you already have added Provider code .
modify your AppDatabase Class as
#ContentProvider(authority = AppDatabase.AUTHORITY,
database = AppDatabase.class,
baseContentUri = AppDatabase.BASE_CONTENT_URI)
#Database(name = AppDatabase.NAME, version = AppDatabase.VERSION)
public class AppDatabase {
public static final String NAME = "AppDatabase"; // we will add the .db extension
public static final int VERSION = 2;
public static final String AUTHORITY = "com.hashx19.pristinekashmir.dbflowcontentprovider";
public static final String BASE_CONTENT_URI = "content://"; }
modify each table you want to use as provider as
#TableEndpoint(name = PostData.ENDPOINT, contentProvider = AppDatabase.class)
#Table(database = AppDatabase.class ,allFields = true ,name = PostData.ENDPOINT)
public class PostData extends BaseModel {
public static final String ENDPOINT = "PostData";
#ContentUri(path = ENDPOINT, type = ContentUri.ContentType.VND_MULTIPLE + ENDPOINT)
public static final Uri CONTENT_URI = Uri.parse(AppDatabase.BASE_CONTENT_URI + AppDatabase.AUTHORITY
+ "/" + ENDPOINT);
#PrimaryKey
public int id;
public String image;
}
For using Content provider as in Cursor Loader use TableName.CONTENT_URI as in this case
CursorLoader cursorLoader = new CursorLoader(getContext(),PostData.CONTENT_URI,projection,null,null,null);

How to open pdf from asset in Android Kitkat only?

I am developing an android app where I have some pdf files stored in asset folder. On click of list items the files open through available pdf viewer. The following code runs fine in versions lower than Kitkat. But as Kitkat have its own Storage Access Framework(SAF) the code only opens the framework not the file.
FileContentProvider.java
public class FileContentProvider extends ContentProvider
{
#Override
public String getType(Uri uri)
{
return "application/pdf";
}
#Override
public AssetFileDescriptor openAssetFile(Uri uri, String mode) throws FileNotFoundException
{
AssetManager am = getContext().getAssets();
String file_name = uri.getLastPathSegment();
if (file_name == null) throw new FileNotFoundException();
AssetFileDescriptor afd = null;
try
{
afd = am.openFd(file_name+ ".mp3");
}
catch (IOException e)
{
e.printStackTrace();
}
return afd;
}
private final static String[] COLUMNS = {OpenableColumns.DISPLAY_NAME, OpenableColumns.SIZE};
#Override
/**
* This function is required for it to work on the Quickoffice at Android 4.4 (KitKat)
*/
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)
{
if (projection == null)
{
projection = COLUMNS;
}
String[] cols = new String[projection.length];
Object[] values = new Object[projection.length];
int i = 0;
for (String col : projection)
{
if (OpenableColumns.DISPLAY_NAME.equals(col))
{
cols[i] = OpenableColumns.DISPLAY_NAME;
values[i++] = uri.getLastPathSegment();
}
else if (OpenableColumns.SIZE.equals(col))
{
cols[i] = OpenableColumns.SIZE;
values[i++] = AssetFileDescriptor.UNKNOWN_LENGTH;
}
}
cols = copyOf(cols, i);
values = copyOf(values, i);
final MatrixCursor cursor = new MatrixCursor(cols, 1);
cursor.addRow(values);
return cursor;
}
private static String[] copyOf(String[] original, int newLength)
{
final String[] result = new String[newLength];
System.arraycopy(original, 0, result, 0, newLength);
return result;
}
private static Object[] copyOf(Object[] original, int newLength)
{
final Object[] result = new Object[newLength];
System.arraycopy(original, 0, result, 0, newLength);
return result;
}
#Override
public boolean onCreate()
{
return true;
}
#Override
public Uri insert(Uri uri, ContentValues values)
{
return null;
}
#Override
public int delete(Uri uri, String selection, String[] selectionArgs)
{
return 0;
}
#Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs)
{
return 0;
}
}
The code block from where it is called:
if(android.os.Build.VERSION.SDK_INT <19) {
i = new Intent(Intent.ACTION_VIEW);
}
else {
i = new Intent();
}
/**Open PDF Forms*/
String fileName = "af1_version_7_december_2013.pdf";
i.setDataAndType(Uri.parse("content://package_name/"+fileName), "application/pdf");
try {
startActivity(i);
}
catch (ActivityNotFoundException e)
{
Toast.makeText(getActivity(), "NO Pdf Viewer", Toast.LENGTH_SHORT).show();
}
After debugging I have seen that for Kitkat the Kitkat specific code in my FileContentProvider.java is not accessed.
Please let me know if anyone have the solution to this problem. My sincere thanks in advance.
Note: This question is not duplicate as previous questions and answers were not Kitkat specefic and after my detailed search I've found that there is no solution in stack overflow to this question as of now.

Way to get ParseObjects to custom Search suggestions in Android

I want to ask, if is there some way to get ParseObjects to Search suggestions-box in Android. I've succesully created recent-query suggestions and it worked well. But right now do I need to put there one string collection from Parse.com while the user is typing -show results, which contain the query which is being typed. I am kind of desperated because I've been searching for it for a week and no result.
Do you have any idea, how to accomplish that?
My in normal ParseQuery in SearchActivity:
ParseQuery<Animal> squery = ParseQuery.getQuery(Animal.class);
squery.whereMatches("animal", query, "i");
squery.findInBackground(new FindCallback<Animal>() {
#Override
public void done(List<Animal> animals, ParseException error) {
if(animals != null){
nAdapter.clear();
for (int i = 0; i < animals.size(); i++) {
mProgressBar = (ProgressBar) findViewById(R.id.search_loading_animals);
mProgressBar.setVisibility(View.INVISIBLE);
nAdapter.add(animals.get(i));
}
}
}
});
SuggestionAdapter to which do i need to implement the ParseQuery:
public class SuggestionProvider extends ContentProvider {
private static final String TAG = "SuggestionProvider";
private static final int SEARCH_SUGGESTIONS = 1;
private static final UriMatcher sURLMatcher = new UriMatcher(
UriMatcher.NO_MATCH);
static {
sURLMatcher.addURI("*", SearchManager.SUGGEST_URI_PATH_QUERY,
SEARCH_SUGGESTIONS);
sURLMatcher.addURI("*", SearchManager.SUGGEST_URI_PATH_QUERY + "/*",
SEARCH_SUGGESTIONS);
}
private static final String[] COLUMNS = new String[] {
"_id",
SearchManager.SUGGEST_COLUMN_TEXT_1,
SearchManager.SUGGEST_COLUMN_INTENT_ACTION,
SearchManager.SUGGEST_COLUMN_QUERY
};
public SuggestionProvider() {
}
#Override
public boolean onCreate() {
return true;
}
#Override
public Cursor query(Uri url, String[] projectionIn, String selection,
String[] selectionArgs, String sort) {
int match = sURLMatcher.match(url);
switch (match) {
case SEARCH_SUGGESTIONS:
String query = url.getLastPathSegment();
MatrixCursor cursor = new MatrixCursor(COLUMNS);
String[] suffixes = { "", "a", " foo", "XXXXXXXXXXXXXXXXX" };
for (String suffix : suffixes) {
Toast.makeText(getContext(), "", Toast.LENGTH_SHORT).show();
addRow(cursor, query + suffix);
}
return cursor;
default:
throw new IllegalArgumentException("Unknown URL: " + url);
}
}
private void addRow(MatrixCursor cursor, String string) {
long id = cursor.getCount();
cursor.newRow().add(id).add(string).add(Intent.ACTION_SEARCH).add(string);
}
#Override
public String getType(Uri url) {
int match = sURLMatcher.match(url);
switch (match) {
case SEARCH_SUGGESTIONS:
return SearchManager.SUGGEST_MIME_TYPE;
default:
throw new IllegalArgumentException("Unknown URL: " + url);
}
}
#Override
public int update(Uri url, ContentValues values, String where, String[] whereArgs) {
throw new UnsupportedOperationException("update not supported");
}
#Override
public Uri insert(Uri url, ContentValues initialValues) {
throw new UnsupportedOperationException("insert not supported");
}
#Override
public int delete(Uri url, String where, String[] whereArgs) {
throw new UnsupportedOperationException("delete not supported");
}
}

How to set up Android's MockContentProvider

I'm currently testing Android's ContentProvider and running into some issues mocking it. I've already spent days on the internet but didn't find any useful examples except of the introduction on the Android Developer Site.
I implemented a ContentProvider and wrote some tests. Everything works here completely fine. The result of the tests are matching my expectations.
public class DirectMessageProviderTest extends ProviderTestCase2<DirectMessageProvider>{
#SmallTest
public void testInsert() {
Log.d(TAG, "testInsert");
/*
* result retrieves twitterId for the newly inserted item
*/
Uri result = provider.insert(
DirectMessageProvider.CONTENT_URI,
createContentValues());
Log.i(TAG, "INSERT; id for newly inserted item: " + result);
assertNotNull("INSERT!!! failed", result);
if (result != null) {
isDirectMessageInserted = true;
}
}
#SmallTest
public void testQuery() {
Log.d(TAG, "testQuery");
Uri uri = Uri.withAppendedPath(
DirectMessageProvider.CONTENT_URI,
String.valueOf(directMessage.getTwitterId()));
/*
* result retrieves a cursor or null
*/
Cursor result = provider.query(
uri,
null,
null,
null,
null);
Log.i(TAG, "QUERY; number of rows inside the cursor: " + result.getCount());
int expected = isDirectMessageInserted ? 1 : 0;
assertEquals("QUERY!!! failed", expected, result.getCount());
}
}
I also implemented a class which capsules the ContentProvider and provides more complex methods than delete, insert, query and update. Take a look!
public class DirectMessageDataAccessImpl implements
DirectMessageDataAccessInterface {
#Override
public boolean isStored(TwitterDirectMessage directMessage)
throws DataAccessException {
Log.d(TAG, "isStored");
try {
Uri uri = Uri.withAppendedPath(
DirectMessageProvider.CONTENT_URI,
String.valueOf(directMessage.getTwitterId()));
Cursor cursor = resolver.query(
uri,
null,
null,
null,
null);
cursor.moveToFirst();
boolean result = (cursor.getCount() > 0 ? true: false);
cursor.close();
return result;
} catch (Exception e) {
Log.e(TAG, e.getMessage(), e);
throw new DataAccessException(e.getMessage());
}
}
}
Finally we`re coming to my problem writing a test for this class. I want to write independent tests for this class using a mocked ContentResolver. I've found this [example] (http://www.androidadb.com/source/npr-android-app-read-only/Npr_Test/src/org/npr/android/util/PlaylistProviderTest.java.html) on the internet and tried to use MockContentResolver.
First of all, I created a new ContentProvider which will retrieve the delete, insert, query and update calls from the tested class, to create the same answer again and again.
public class DirectMessageDataAccessTest extends ProviderTestCase2<DirectMessageProvider>{
private ContentProvider provider = new ContentProvider() {
#Override
public int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
Log.d(TAG, "update");
return 0;
}
#Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
Log.w(TAG, "query");
return null;
}
#Override
public boolean onCreate() {
Log.d(TAG, "onCreate");
return false;
}
#Override
public Uri insert(Uri uri, ContentValues values) {
Log.d(TAG, "insert");
return null;
}
#Override
public String getType(Uri uri) {
Log.d(TAG, "getType");
return null;
}
#Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
Log.d(TAG, "delete");
return 0;
}
};
}
After this, I modified my setUp Method in order to create a MockContentResolver and added my ContentProvider above
#Override
protected void setUp() throws Exception {
super.setUp();
/*
* MockContentResolver overrides Android's normal way of resolving providers by authority
*/
MockContentResolver resolver = new MockContentResolver();
/*
* Adds access to a provider based on its authority
*/
resolver.addProvider(DirectMessageProvider.AUTHORITY, provider);
context = new IsolatedContext(resolver, getContext());
this.setContext(context);
}
Last but not least, I wrote a test case for my isStored Method.
public void testIsStored() {
Log.d(TAG, "testIsStored");
TwitterDirectMessage directMessage = new TwitterDirectMessage();
directMessage.setTwitterId(123456);
DirectMessageDataAccessInterface dataAccess =
new DirectMessageDataAccessImpl(context);
try {
assertFalse(dataAccess.isStored(directMessage));
} catch (DataAccessException e) {
e.printStackTrace();
fail("...");
}
}
Unfortunately, android.content.ContentProvider always throws a NullPointerException. I'm calling resolver.query(...)in line 72 of DirectMessageDataAccessImpl
E/DirectMessageDataAccessImpl(1758): null
E/DirectMessageDataAccessImpl(1758): java.lang.NullPointerException
E/DirectMessageDataAccessImpl(1758): at android.content.ContentProvider$Transport.enforceReadPermission(ContentProvider.java:284)
E/DirectMessageDataAccessImpl(1758): at android.content.ContentProvider$Transport.query(ContentProvider.java:177)
E/DirectMessageDataAccessImpl(1758): at android.content.ContentResolver.query(ContentResolver.java:311)
E/DirectMessageDataAccessImpl(1758): at xxx.xxxxx.xxxxxxx.app.database.dataaccess.implementation.DirectMessageDataAccessImpl.isStored(DirectMessageDataAccessImpl.java:72)
E/DirectMessageDataAccessImpl(1758): at xxx.xxxxx.xxxxxxx.app.test.dataaccess.DirectMessageDataAccessTest.testIsStored(DirectMessageDataAccessTest.java:107)
In constructor you should set
public YourClass() {
super(DBProvider.class, "com.yourpackage.main");// class of Your Content provider and application package
}
and then just call
MockContentResolver mockContentResolver = getMockContentResolver();
assertNotNull(mockContentResolver);
in a tests

Categories

Resources