Alright, I would like to make a class that can kinda make working with Content Providers a little easier, especially while working with contacts. I have something of a base layout, but its erroring out when I try to initiate cr. How would I be able to get something like this working?
Also, how does it look in general? From a design and efficiency perspective, as well as being an easy to use utility, would this be a good way to go about doing what I'd like to achieve?
public class ContactUtils {
private Uri uri = ContactsContract.Contacts.CONTENT_URI;
private ContentResolver cr = new ContentResolver(this);
public String getDisplayName(int id) {
String name = null;
String[] projection = new String[] {ContactsContract.Contacts.DISPLAY_NAME};
String selection = ContactsContract.Contacts.IN_VISIBLE_GROUP + " = '" + ("1") + "'";
Cursor contact = cr.query(this.uri, projection, selection, null, null);
while (contact.moveToFirst()) {
name = contact.getString(contact.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));
}
return name;
}
}
The constructor of ContentResolver takes a Context a its single parameter. Your ContactUtils class does not extend Context and can therefore not be used as one.
Related
I am working on a project using Content Provider for DB.
I am able to fetch all rows using the query mentioned below.
My problem is I want to sum up a column for all rows fetched.
I am querying as :
String query = WorkTable.ENTRY_TIME + " = ?"
String projection = "new String[]{WorkoutLogTable.STEPS}";
Cursor cursor = getContentResolver()
.query(
LogProvider.WORK_LOG,
projection,
query,
new String[]{dateString},
null
);
I want the sum of WorkoutLogTable.STEPS. Projection needs string[] as parameter, so how can I sum up the STEPS value?
Edit
I used a projection:
String projection = new String[]{"sum(WorkoutLogTable.STEPS}) as total"};
But it's also not working.
Solution:
I was doing a mistake by making the whole part as string.
So I have resolved so:
String projection = new String[]{"sum(steps) as total"}; // steps is my column name and I was fetching it by WorkoutLogTable.STEPS which was wrong
Or another solution can be using Dynamic string (from cricket_007 answer)
Projection needs string[] as parameter,
Right, so why is your projection variable a String? This statement won't even compile.
String projection = "new String[]{"sum(WorkoutLogTable.STEPS}) as total"};
Maybe you meant this?
String[] projection = new String[] { "sum(" + WorkoutLogTable.STEPS + ") as total" };
You need to use an actual String[] object, not a String that has the content of "String[] { ... }"
String selection = WorkTable.ENTRY_TIME + " = ?"
String[] projection = new String[] { "sum(" + WorkoutLogTable.STEPS + ")" };
String[] selectionArgs = new String[] { dateString };
Cursor cur = getContentResolver().query(
LogProvider.WORK_LOG,
projection,
selection,
null, null);
Is this a content provider from another app? If you are writing the content provider, I would recommend that you add another URL specifically for the summary query and do your sum function in the query inside the content provider. Then just use the alternate URL when you go through the content resolver.
I have gone through a lot of stackoverflow questions but I couldn't find an answer to this. There is an answer for Image files but that doesn't work in my case.
So I have the absolute path of the file using file.getAbsolutePath(). But I need to convert it to contentUri so that below query works fine.
Cursor tempCursor = context.getContentResolver().query(uri,
proj, null, null, null);
It is not working. I tried Uri.parse(contentUri) but that doesn't give the content uri I guess. Please help me, I am stuck since a long time. Thanks !!
You do not use the get.absolute etc. Simply query the Medfiastore.Audio etc and bring back _id and _DATA. _id is the song id and _DATA has the full path and track
below a piece of code which you could use. Just feed it the track name
public String getThisTrackId(Context context, String trackName) {
ContentResolver cr = context.getContentResolver();
final String _id = MediaStore.Audio.Media._ID;
final String path = MediaStore.Audio.Media.DATA;
final String[] columns = { _id };
final String[] trackname = { "%"+ trackName +"%" };
String where = path + " LIKE ?";
String strtrack_id = null;
Cursor crs =cr.query(uri, columns, where, trackname, null);
if(crs!= null && crs.moveToFirst()){
strtrack_id = crs.getString(crs.getColumnIndexOrThrow(_id));
crs.close();
}
return strtrack_id;
}
I'm implementing my own SearchRecentSuggestionsProvider and everything's working except one thing: I can't get the device search to display icons for the results. I'd like to display images from my application's data folder (located at /{sdcard}/Android/data/package_name/files/)
According to the documentation, it's achievable by using SearchManager.SUGGEST_COLUMN_ICON_1, and it apparently supports a number of schemes, including ContentResolver.SCHEME_FILE, which is file. Here's a quote from the official docs:
Column name for suggestions cursor. Optional. If your cursor includes this column, then all suggestions will be provided in a format that includes space for two small icons, one at the left and one at the right of each suggestion. The data in the column must be a resource ID of a drawable, or a URI in one of the following formats:
content (SCHEME_CONTENT)
android.resource (SCHEME_ANDROID_RESOURCE)
file (SCHEME_FILE)
I've tried a number of obvious things, including manual creation of the file URI and automated creation using Uri.Builder(). None of this worked.
I also found someone else asking about the same thing on Google Groups, and it's sadly unanswered: https://groups.google.com/forum/#!topic/android-developers/MJj7GIaONjc
Does anyone have any experience in getting the device search to display local images from the device?
UPDATE (December 15):
I've just tried using the ContentProvider with a SearchView as the searchable info, and it works exactly as expected - including the cover art images. Still, global search doesn't show it...
I had a similar issue and could not make the other solutions work. I finally substituted the cursor with a new one containing the data I needed in query().
public class RecentQueriesProvider extends SearchRecentSuggestionsProvider {
public final static String AUTHORITY = "com.package.RecentQueriesProvider";
public final static int MODE = DATABASE_MODE_QUERIES;
public RecentQueriesProvider() {
setupSuggestions(AUTHORITY, MODE);
}
// We override query() to replace the history icon in the recent searches suggestions. We create a new cursor
#Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
Cursor superCursor = super.query(uri, projection, selection, selectionArgs, sortOrder);
Uri iconUri = Uri.parse("android.resource://" + getContext().getPackageName() + "/drawable/ic_action_time");
MatrixCursor newCursor = new MatrixCursor(superCursor.getColumnNames());
superCursor.moveToFirst();
while (superCursor.moveToNext()){
newCursor.addRow(new Object[]{
superCursor.getInt(superCursor.getColumnIndex(SearchManager.SUGGEST_COLUMN_FORMAT)),
iconUri,
superCursor.getString(superCursor.getColumnIndex(SearchManager.SUGGEST_COLUMN_TEXT_1)),
superCursor.getString(superCursor.getColumnIndex("suggest_intent_query")),
superCursor.getInt(superCursor.getColumnIndex("_id"))
});
}
return newCursor;
}
}
One way is to copy source code from android.content.SearchRecentSuggestionsProvider, place it in your class that extends ContentProvider, and customize setupSuggestions(String, int). Specifically, you would be changing this:
Uri uriFile = Uri.fromFile(new File("path/to/file"));
mSuggestionProjection = new String [] {
"0 AS " + SearchManager.SUGGEST_COLUMN_FORMAT,
// Here, you would return a file uri: 'uriFile'
"'android.resource://system/"
+ com.android.internal.R.drawable.ic_menu_recent_history + "' AS "
+ SearchManager.SUGGEST_COLUMN_ICON_1,
"display1 AS " + SearchManager.SUGGEST_COLUMN_TEXT_1,
"query AS " + SearchManager.SUGGEST_COLUMN_QUERY,
"_id"
};
I prefer the following though. Extend SearchRecentSuggestionsProvider and override the query(...) method. Here, intercept SearchManager.SUGGEST_URI_PATH_QUERY and return a cursor.
public class SearchSuggestionProvider extends SearchRecentSuggestionsProvider {
private UriMatcher matcher;
private static final int URI_MATCH_SUGGEST = 1;
public SearchSuggestionProvider() {
super();
matcher = new UriMatcher(UriMatcher.NO_MATCH);
// Add uri to return URI_MATCH_SUGGEST
matcher.addURI(SearchSuggestionProvider.class.getName(),
SearchManager.SUGGEST_URI_PATH_QUERY, URI_MATCH_SUGGEST);
setupSuggestions(SearchSuggestionProvider.class.getName(),
DATABASE_MODE_QUERIES);
}
#Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
// special case for actual suggestions (from search manager)
if (matcher.match(uri) == URI_MATCH_SUGGEST) {
// File to use
File f = new File("/path/to/file");
Uri uriFile = Uri.fromFile(f);
final String[] PROJECTION = new String[] {
"_id",
"display1 AS " + SearchManager.SUGGEST_COLUMN_TEXT_1,
"query AS " + SearchManager.SUGGEST_COLUMN_QUERY,
"'" + uriFile + "'" + " AS " + SearchManager.SUGGEST_COLUMN_ICON_1,
};
final Uri URI = Uri.parse("content://" +
SearchSuggestionProvider.class.getName() + "/suggestions");
// return cursor
return getContext().getContentResolver().query(
URI,
PROJECTION,
"display1 LIKE ?",
new String[] {selectionArgs[0] + "%"},
"date DESC");
}
// Let super method handle the query if the check fails
return super.query(uri, projection, selection, selectionArgs, sortOrder);
}
}
I'm trying to get my ContentResolver to run this query:
select * from myTable limit 1 offset 2
The only query method in ContentResolver is:
resolver.query(uri, projection, selection, selectionArgs, sortOrder);
I've tried:
final Cursor c = resolver.query(
MyTable.CONTENT_URI,
MyTable.PROJECTION,
" ? ?",
new String[] {"1", "2"},
null);
Which just throws an IllegaLArgumentException.
What is the correct way of achieving this?
I put the LIMIT clause in the sordOrder parameter, I've also seen the same thing done by others but not sure if its 100% correct:
final Cursor c = resolver.query(
MyTable.CONTENT_URI,
MyTable.PROJECTION,
null,
null,
" limit 1 offset 2");
I put the limit clause as a query parameter using the syntax 'limit = offset, limit':
Cursor c = context.getContentResolver().query(
MyTable.CONTENT_URI.buildUpon().encodedQuery("limit="+offset+","+limit).build(),
MyTable.PROJECTION,
null,
null,
null);
It works at least with MediaStore uris. Be careful of not encoding the "," or it won't work.
If you are providing your content provider, then you can use android.net.Uri.Builder#appendQueryParameter for providing limit and offset as query parameters, which the content provider can use while building the query.
public class MyProvider extends ContentProvider {
public static final String QUERY_PARAMETER_LIMIT = "limit";
public static final String QUERY_PARAMETER_OFFSET = "offset";
public Cursor query(Uri uri, ...) {
String limit = uri.getQueryParameter(QUERY_PARAMETER_LIMIT);
String offset = uri.getQueryParameter(QUERY_PARAMETER_OFFSET);
SQLiteQueryBuilder builder = new SQLiteQueryBuilder();
// set the table name,...
// leaving handling of null conditions as an exercise to the reader.
String limitString = offset + "," + limit;
Cursor c = qb.query(db, projection, selection, selectionArgs, null, null, sortOrder, limitString);
//...
return c;
}
}
while building the query:
private static final Uri CONTENT_URI = MyProvider.CONTENT_URI.buildUpon()
.appendQueryParameter(MyProvider.QUERY_PARAMETER_LIMIT,
String.valueOf(limit))
.appendQueryParameter(MyProvider.QUERY_PARAMETER_OFFSET,
String.valueOf(offset))
.build();
note that the android.net.Uri.Builder#appendQueryParameter encodes the value to prevent sql injection.
References:
http://laviefrugale.blogspot.com/2012/01/using-limit-with-android-contentprovider.html
http://www.sqlite.org/lang_select.html
https://stackoverflow.com/a/12476458/1523910 + #eocanha's answer
When I tried to use the limit String [see limit String below] using the following:
StringBuilder sbLimit = new StringBuilder().append(" ").append(i_offset).append(" , ").append(i_limit);
String limit = sbLimit .toString()
This gave me good results in combination with the select queries , sorting and grouping.
I am trying to create an app which simply offers an edittext and imagebutton. If the butten gets clicked, the idea is that an album is added to the Playlist, named in the edittext box. Albums should be selected randomly. Goes without saying that the album tracks should be in the correct order.
I can add more functionality later eg. save, overwrite, delete etc.
I have the interface but am struggling with the code. I sort of get the concept of ContentProviders.
so the code needs to:
access the Playlists, which I believe is achieved by using MediaStore.Audio.Playlists
access the Albums, which I believe is achieved by using MediaStore.Audio.Albums
add to the Playlist
I have the following code (most bits obtained from this site. Thanks btw) to access the Playlist but it crashes with a Null Exception error.
public void checkforplaylists()
{
//Get a cursor over all playlists.
final ContentResolver resolver= MediaProvider.mContentResolver;
final Uri uri=MediaStore.Audio.Playlists.INTERNAL_CONTENT_URI;
final String id=MediaStore.Audio.Playlists._ID;
final String name=MediaStore.Audio.Playlists.NAME;
final String[]columns={id,name};
final Cursor playlists= resolver.query(uri, columns, null, null, null);
if(playlists==null)
{
Log.e(TAG,"Found no playlists.");
return;
}
return;
}
Anyone who can help?
I think you mean NullPointerException, which means one of your assignments is null and then you try to access a member of the object you intended it to be. Most likely it is resolver, but to be sure you need the line number reported and/or to step through that with a debugger.
This works. When using the ContentResolver, the Context (this) is required.
public void checkforplaylists(Context context)
{
ContentResolver cr = context.getContentResolver();
final Uri uri=MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI;
final String id=MediaStore.Audio.Playlists._ID;
final String name=MediaStore.Audio.Playlists.NAME;
final String[]columns={id,name};
final Cursor playlists= cr.query(uri, columns, null, null, null);
if(playlists==null)
{
Log.e(TAG,"Found no playlists.");
return;
}
Log.e(TAG,"Found playlists.");
return;
}
use this code, will work
public boolean addPlaylist(String pname) {
Uri playlists = MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI;
Cursor c = resolver.query(playlists, new String[] { "*" }, null, null,
null);
long playlistId = 0;
c.moveToFirst();
do {
String plname = c.getString(c
.getColumnIndex(MediaStore.Audio.Playlists.NAME));
if (plname.equalsIgnoreCase(pname)) {
playlistId = c.getLong(c
.getColumnIndex(MediaStore.Audio.Playlists._ID));
break;
}
} while (c.moveToNext());
c.close();
if (playlistId != 0) {
Uri deleteUri = ContentUris.withAppendedId(playlists, playlistId);
Log.d(TAG, "REMOVING Existing Playlist: " + playlistId);
// delete the playlist
resolver.delete(deleteUri, null, null);
}
Log.d(TAG, "CREATING PLAYLIST: " + pname);
ContentValues v1 = new ContentValues();
v1.put(MediaStore.Audio.Playlists.NAME, pname);
v1.put(MediaStore.Audio.Playlists.DATE_MODIFIED,
System.currentTimeMillis());
Uri newpl = resolver.insert(playlists, v1);
Log.d(TAG, "Added PlayLIst: " + newpl);
flag=true;
return flag;
}