Alternative to MediaStore.Playlists.Members.moveItem - android

I've been using the following code to remove an item from a playlist in my Android app:
private void removeFromPlaylist(long playlistId, int loc)
{
ContentResolver resolver = getApplicationContext().getContentResolver();
Uri uri = MediaStore.Audio.Playlists.Members.getContentUri("external", playlistId);
resolver.delete(uri, MediaStore.Audio.Playlists.Members.PLAY_ORDER+" = "+loc, null);
for(int i=loc+1;i<playSongIDs.length;i++) {
MediaStore.Audio.Playlists.Members.moveItem(resolver,playlistId,i, i-1);
}
}
I'm currently using the Android 2.2 library and this is the only thing that I need to change to use Android 2.1. Is there an alternate method for removing an item from a playlist and adjusting the order of the items after the deleted one?

looking at the code of the MediaStore we came out with this solution that seems to work fine:
/**
* Convenience method to move a playlist item to a new location
* #param res The content resolver to use
* #param playlistId The numeric id of the playlist
* #param from The position of the item to move
* #param to The position to move the item to
* #return true on success
*/
private boolean moveItem(ContentResolver res, long playlistId, int from, int to) {
Uri uri = MediaStore.Audio.Playlists.Members.getContentUri("external",
playlistId)
.buildUpon()
.appendEncodedPath(String.valueOf(from))
.appendQueryParameter("move", "true")
.build();
ContentValues values = new ContentValues();
values.put(MediaStore.Audio.Playlists.Members.PLAY_ORDER, to);
return res.update(uri, values, null, null) != 0;
}

Related

How to implement Image gallery with single image representing file in image directory

I am trying to implement a feature like Instagram or WhatsApp, where the thumbnail of a single image that exists in a folder in android, is shown on top of a list item, more like a sample of what kinds of image are in the folder.
Help me to understand this feature.
How I implemented it. It might not be the best though, but it works.
I fetched the URIs of all the images using MediaStore, you can learn how to use it here.
The First step was done in a background thread to prevent it from blocking the UI thread.
I sorted out the images I got, grouping them in a List<Image>, which would represent a single directory.
I then added the List<Image> into a List<List<Image>>, which served as the overall images that were fetched and have their total size which I used later to track the number of images in the directory.
The code is below.
#Override
public void run() {
Uri storageUri;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
storageUri = MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL);
} else {
storageUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
}
// the queries to the MediaStore API (The image details or metadata I need
String[] projection = {
MediaStore.Images.Media._ID,
MediaStore.Images.Media.BUCKET_DISPLAY_NAME,
MediaStore.Images.Media.SIZE,
MediaStore.Images.Media.DISPLAY_NAME};
// now query the MediaStore API using ContentResolver
Cursor imgCursor = getApplicationContext().getContentResolver().query(storageUri, projection, null, null, null);
int bucketId = imgCursor.getColumnIndexOrThrow(MediaStore.Images.Media._ID);
int imgSize = imgCursor.getColumnIndexOrThrow(MediaStore.Images.Media.SIZE);
int name = imgCursor.getColumnIndexOrThrow(MediaStore.Images.Media.DISPLAY_NAME);
int bucketName = imgCursor.getColumnIndexOrThrow(MediaStore.Images.Media.BUCKET_DISPLAY_NAME);
// directoryDictionary is a temporary list of directory names that was found, while querying the MediaStore API
List<String> directoryDictionary = new ArrayList<>();
// generalList is just a list that would represent a general image list, where all images can be found. Just like Whatsapp
List<Image> generalList = new ArrayList<>();
while (imgCursor.moveToNext()) {
long id = imgCursor.getLong(bucketId);
int size = imgCursor.getInt(imgSize);
String fileName = imgCursor.getString(name);
String folderName = imgCursor.getString(bucketName);
// As recommended by the Android developers doc
Uri contentUri = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, id);
// a single image
Image currentImage = new Image(contentUri, size, fileName, folderName);
// add all images to the general image list, but modifying the directory name
Image genImage = new Image(contentUri, size, fileName, "All Media");
generalList.add(genImage);
int directoryIndex = CollectionUtils.linearSearch(directoryDictionary, folderName);
// if search result (directoryIndex) passes this test, then it means that there is
// no such directory in list of directory names
if (directoryIndex < 0) {
imageDirectoryList.add(new ArrayList<>());
directoryDictionary.add(folderName);
directoryIndex = CollectionUtils.linearSearch(directoryDictionary, folderName);
if (directoryIndex >= 0)
imageDirectoryList.get(directoryIndex).add(currentImage);
} else {
imageDirectoryList.get(directoryIndex).add(currentImage);
}
}
//...then add it if the image list of folder is > 2
if (imageDirectoryList.size() > 2) imageDirectoryList.add(0, generalList);
imgCursor.close();
runOnUiThread(() -> {
// imageAdapter is the RecyclerView's list Adapter.
// notifyDataSetChanged() must be call to refresh list.
imageAdapter.notifyDataSetChanged();
// doViewUpdate was just used to turn on and off the visibility of some views
doViewUpdate();
});
}

How to create programatic bookmark into browser using Android sdk?

I've seen apps doing this, but I don't have a clue where to start. Any hints? Some code snippets will be appreciated.
/**
* Add a bookmark to the database.
*
* #param context
* Context of the calling Activity. This is used to make Toast confirming that the bookmark has been added. If the caller provides null, the Toast will not be shown.
* #param cr
* The ContentResolver being used to add the bookmark to the db.
* #param url
* URL of the website to be bookmarked.
* #param name
* Provided name for the bookmark.
* #param thumbnail
* A thumbnail for the bookmark.
* #param retainIcon
* Whether to retain the page's icon in the icon database. This will usually be <code>true</code> except when bookmarks are added by a settings restore agent.
*/
static void addBookmark(Context context, ContentResolver cr, String url, String name, Bitmap thumbnail, boolean retainIcon) {
final String WHERE_CLAUSE = "url = ? OR url = ? OR url = ? OR url = ?";
final String WHERE_CLAUSE_SECURE = "url = ? OR url = ?";
String[] SELECTION_ARGS;
// Want to append to the beginning of the list
long creationTime = new Date().getTime();
// First we check to see if the user has already visited this
// site. They may have bookmarked it in a different way from
// how it's stored in the database, so allow different combos
// to map to the same url.
boolean secure = false;
String compareString = url;
if (compareString.startsWith("http://")) {
compareString = compareString.substring(7);
} else if (compareString.startsWith("https://")) {
compareString = compareString.substring(8);
secure = true;
}
if (compareString.startsWith("www.")) {
compareString = compareString.substring(4);
}
if (secure) {
SELECTION_ARGS = new String[2];
SELECTION_ARGS[0] = "https://" + compareString;
SELECTION_ARGS[1] = "https://www." + compareString;
} else {
SELECTION_ARGS = new String[4];
SELECTION_ARGS[0] = compareString;
SELECTION_ARGS[1] = "www." + compareString;
SELECTION_ARGS[2] = "http://" + compareString;
SELECTION_ARGS[3] = "http://" + SELECTION_ARGS[1];
}
Cursor cursor = cr.query(Browser.BOOKMARKS_URI, Browser.HISTORY_PROJECTION, secure ? WHERE_CLAUSE_SECURE : WHERE_CLAUSE, SELECTION_ARGS, null);
ContentValues map = new ContentValues();
if (cursor.moveToFirst() && cursor.getInt(Browser.HISTORY_PROJECTION_BOOKMARK_INDEX) == 0) {
// This means we have been to this site but not bookmarked
// it, so convert the history item to a bookmark
map.put(Browser.BookmarkColumns.CREATED, creationTime);
map.put(Browser.BookmarkColumns.TITLE, name);
map.put(Browser.BookmarkColumns.BOOKMARK, 1);
// map.put(Browser.BookmarkColumns.THUMBNAIL, bitmapToBytes(thumbnail));
cr.update(Browser.BOOKMARKS_URI, map, "_id = " + cursor.getInt(0), null);
} else {
int count = cursor.getCount();
boolean matchedTitle = false;
for (int i = 0; i < count; i++) {
// One or more bookmarks already exist for this site.
// Check the names of each
cursor.moveToPosition(i);
if (cursor.getString(Browser.HISTORY_PROJECTION_TITLE_INDEX).equals(name)) {
// The old bookmark has the same name.
// Update its creation time.
map.put(Browser.BookmarkColumns.CREATED, creationTime);
cr.update(Browser.BOOKMARKS_URI, map, "_id = " + cursor.getInt(0), null);
matchedTitle = true;
break;
}
}
if (!matchedTitle) {
// Adding a bookmark for a site the user has visited,
// or a new bookmark (with a different name) for a site
// the user has visited
map.put(Browser.BookmarkColumns.TITLE, name);
map.put(Browser.BookmarkColumns.URL, url);
map.put(Browser.BookmarkColumns.CREATED, creationTime);
map.put(Browser.BookmarkColumns.BOOKMARK, 1);
map.put(Browser.BookmarkColumns.DATE, 0);
// map.put(Browser.BookmarkColumns.THUMBNAIL, bitmapToBytes(thumbnail));
int visits = 0;
if (count > 0) {
// The user has already bookmarked, and possibly
// visited this site. However, they are creating
// a new bookmark with the same url but a different
// name. The new bookmark should have the same
// number of visits as the already created bookmark.
visits = cursor.getInt(Browser.HISTORY_PROJECTION_VISITS_INDEX);
}
// Bookmark starts with 3 extra visits so that it will
// bubble up in the most visited and goto search box
map.put(Browser.BookmarkColumns.VISITS, visits + 3);
cr.insert(Browser.BOOKMARKS_URI, map);
}
}
if (retainIcon) {
WebIconDatabase.getInstance().retainIconForPageUrl(url);
}
cursor.close();
}
You can see the OS code here

How to read songs from Google cloud or device

Big picture: GUI shows user a list of their playlists. User picks one. Program passes chosen playlist to next activity which displays the songs in that playlist.
Problem: I can display the playlists and register the users choice, but I can't seem to display the songs of that play list.
Yes, I've see the following questions:
How to query for songs in playlists on Android SDK?
Given an Android music playlist name, how can one find the songs in the playlist?
What is the String 'volumeName' argument of MediaStore.Audio.Playlists.Members.getContentUri referring to?
As you can see in my code, I've done my best to implement those solutions, but to no avail.
Things to keep in mind: I'm testing this on a Galaxy Nexus, so no SDcard. Just internal storage and music in the cloud. I need it to work in any scenario (internal, external, or cloud). It currently works in none of those.
//#SuppressWarnings ("serial)")
public class CreationActivity extends Activity {
private final String [] STAR= {"*"};
//reads in all songs to an array
#Override
public void onCreate (Bundle savedInstanceState){
super.onCreate(savedInstanceState);
//set layout view and assign to variable
setContentView(R.layout.creation);
TableLayout myLayout = (TableLayout)findViewById(R.id.creationLayout);
try {
Bundle extras = getIntent().getExtras();
if (extras!=null){
//get the desired playlist and ID
String playlist = extras.getString("playlist");
Long playlistID = extras.getLong("playlistID");
ArrayList<song> songs = new ArrayList<song>();
//read in the songs from the playlist
String[] proj = {MediaStore.Audio.Playlists.Members.TITLE,
MediaStore.Audio.Playlists.Members.ARTIST,
MediaStore.Audio.Playlists.Members.DURATION};
//method 1
Cursor songCursor = getContentResolver().query(MediaStore.Audio.Playlists.Members.getContentUri(null,playlistID),
proj,
null,
null,
null);
//method 2
/*
Cursor songCursor = getContentResolver().query(Uri.parse("content://com.google.android.music.MusicContent/playlists/members"),
proj,
null,
null,
null);
*/
//method 3
/*
Uri membersUri = MediaStore.Audio.Playlists.Members.getContentUri("internal", playlistID);
Cursor membersCursor = managedQuery(membersUri, STAR, null, null, null);
*/
//then this part with methods 1 and 2
/*
if (songCursor.getCount() > 0) {
songCursor.moveToFirst();
do {
song currSong = new song();
currSong.title = songCursor.getString(0);
currSong.artist = songCursor.getString(1);
songs.add(currSong);
} while (songCursor.moveToNext());
}
songCursor.close();
*/
//or this part with method 3
/*
membersCursor.moveToFirst();
for(int s= 0; s<membersCursor.getCount(); s++,
membersCursor.moveToNext()){
song currSong = new song();
currSong.title = songCursor.getString(0);
currSong.artist = songCursor.getString(1);
songs.add(currSong);
}
membersCursor.close();
*/
}else{
Toast.makeText(getBaseContext(), "No songs",Toast.LENGTH_LONG).show();
}
} catch (NumberFormatException e){
}
}
}
No errors during compiling. But "Unfortunately Music App has unexpectedly quit." every time.
Thanks for the help!
I figured it out. The key was to use the playlist ID as a string immediately within the URI. See code below.
This is the part that will get the playlist names and IDs:
String[] proj = {MediaStore.Audio.Playlists.NAME, MediaStore.Audio.Playlists._ID};
Uri playlistUri = Uri.parse("content://com.google.android.music.MusicContent/playlists");
Cursor playlistCursor = getContentResolver().query(playlistUri, proj, null, null, null);
if (playlistCursor.getCount() > 0) {
playlistCursor.moveToFirst();
do {
nameList.add(playlistCursor.getString(0));
idList.add(playlistCursor.getLong(1));
} while (playlistCursor.moveToNext());
}
Then once you have the playlist ID you can query for the songs in the playlist. This is the part of code that actually queries for the info and puts it all in an array list. NOTE: "song" is a class I have defined elsewhere, where readSong is a method that assigns values to various values (title, artist, etc).
ArrayList<song> songs = new ArrayList<song>();
//read songs into library from the correct playlist
String[] proj = {MediaStore.Audio.Playlists.Members.TITLE, MediaStore.Audio.Playlists.Members.ARTIST, MediaStore.Audio.Playlists.Members.DURATION, MediaStore.Audio.Playlists.Members._ID};
Uri songUri = Uri.parse("content://com.google.android.music.MusicContent/playlists/" + playlistID + "/members");
Cursor songCursor = getContentResolver().query(songUri, proj, null, null, null);
if (songCursor.getCount() > 0) {
songCursor.moveToFirst();
do {
//create dummy song
song currSong = new song();
//read info to dummy var
currSong.readSong(songCursor);
//add instance to collection
songs.add(currSong);
} while (songCursor.moveToNext());
}
songCursor.close();
I hope this helps anybody else who was struggling with this!! Let me know if you have any comments on my method or ways to make it better!

Getting a list of available Ringtones in Android

I've seen plenty of examples of how to set a default ringtone, but what I'm more interested in is being able populate a drop down box list filled with the available ringtones on the phone. So the list that people see when they change their ringtone in the android settings, I want to be able to list all of those.
The closest thing I've found is here, but again this is just for setting the default ringtone. Any ideas anyone? It can be in or out of ringtonemanager.
This will return you the title and uri of all the ringtones available. Do with them what you wish!
public Map<String, String> getNotifications() {
RingtoneManager manager = new RingtoneManager(this);
manager.setType(RingtoneManager.TYPE_RINGTONE);
Cursor cursor = manager.getCursor();
Map<String, String> list = new HashMap<>();
while (cursor.moveToNext()) {
String notificationTitle = cursor.getString(RingtoneManager.TITLE_COLUMN_INDEX);
String notificationUri = cursor.getString(RingtoneManager.URI_COLUMN_INDEX) + "/" + cursor.getString(RingtoneManager.ID_COLUMN_INDEX);
list.put(notificationTitle, notificationUri);
}
return list;
}
RingtoneManager is what you are looking for. You just need to use setType to set TYPE_RINGTONE and then iterate over the Cursor provided by getCursor.
This is a working example of an hypothetical method that returns an array of URIs, with the only slight difference that it's looking for alarms instead of ringtones:
RingtoneManager ringtoneMgr = new RingtoneManager(this);
ringtoneMgr.setType(RingtoneManager.TYPE_ALARM);
Cursor alarmsCursor = ringtoneMgr.getCursor();
int alarmsCount = alarmsCursor.getCount();
if (alarmsCount == 0 && !alarmsCursor.moveToFirst()) {
return null;
}
Uri[] alarms = new Uri[alarmsCount];
while(!alarmsCursor.isAfterLast() && alarmsCursor.moveToNext()) {
int currentPosition = alarmsCursor.getPosition();
alarms[currentPosition] = ringtoneMgr.getRingtoneUri(currentPosition);
}
alarmsCursor.close();
return alarms;

Create Browser-Bookmark from app

I want to create a bookmark in the stock android-browser from my own application. How can I do this?
I only found the Browser.saveBookmark-Method (api-doc) but this displays a new window where the user can change the data. As I want to import bookmarks from a external data-source I want to save the bookmark directly and not ask the user for input.
If you just want to allow the user to add a bookmark, android.provider.Browser.saveBookmark() is what you want. But it looks like you're wanting to do mass updates, so that's probably not enough since it just opens the browser's bookmarks page.
AFAIK there is no open API that ties directly into the browser's bookmarks. However, there is a content resolver for it which can be accessed android.provider.Browser.BOOKMARKS_URI. Once you've resolved the provider you can manipulate bookmarks by running queries, provided you have the com.android.browser.permission.READ_HISTORY_BOOKMARKS and com.android.browser.permission.WRITE_HISTORY_BOOKMARKS permissions.
If you're unfamiliar with content providers, they can get kinda hairy (doubly so if you're unfamiliar with SQL). However, the knowledge base has some good articles on them, and a quick google for "android content provider tutorial" should get you well on your way.
I took the following code from Android implementation (and disabled the "bookmark added" toast):
/**
* Add a bookmark to the database.
*
* #param context
* Context of the calling Activity. This is used to make Toast confirming that the bookmark has been added. If the caller provides null, the Toast will not be shown.
* #param cr
* The ContentResolver being used to add the bookmark to the db.
* #param url
* URL of the website to be bookmarked.
* #param name
* Provided name for the bookmark.
* #param thumbnail
* A thumbnail for the bookmark.
* #param retainIcon
* Whether to retain the page's icon in the icon database. This will usually be <code>true</code> except when bookmarks are added by a settings restore agent.
*/
static void addBookmark(Context context, ContentResolver cr, String url, String name, Bitmap thumbnail, boolean retainIcon) {
final String WHERE_CLAUSE = "url = ? OR url = ? OR url = ? OR url = ?";
final String WHERE_CLAUSE_SECURE = "url = ? OR url = ?";
String[] SELECTION_ARGS;
// Want to append to the beginning of the list
long creationTime = new Date().getTime();
// First we check to see if the user has already visited this
// site. They may have bookmarked it in a different way from
// how it's stored in the database, so allow different combos
// to map to the same url.
boolean secure = false;
String compareString = url;
if (compareString.startsWith("http://")) {
compareString = compareString.substring(7);
} else if (compareString.startsWith("https://")) {
compareString = compareString.substring(8);
secure = true;
}
if (compareString.startsWith("www.")) {
compareString = compareString.substring(4);
}
if (secure) {
SELECTION_ARGS = new String[2];
SELECTION_ARGS[0] = "https://" + compareString;
SELECTION_ARGS[1] = "https://www." + compareString;
} else {
SELECTION_ARGS = new String[4];
SELECTION_ARGS[0] = compareString;
SELECTION_ARGS[1] = "www." + compareString;
SELECTION_ARGS[2] = "http://" + compareString;
SELECTION_ARGS[3] = "http://" + SELECTION_ARGS[1];
}
Cursor cursor = cr.query(Browser.BOOKMARKS_URI, Browser.HISTORY_PROJECTION, secure ? WHERE_CLAUSE_SECURE : WHERE_CLAUSE, SELECTION_ARGS, null);
ContentValues map = new ContentValues();
if (cursor.moveToFirst() && cursor.getInt(Browser.HISTORY_PROJECTION_BOOKMARK_INDEX) == 0) {
// This means we have been to this site but not bookmarked
// it, so convert the history item to a bookmark
map.put(Browser.BookmarkColumns.CREATED, creationTime);
map.put(Browser.BookmarkColumns.TITLE, name);
map.put(Browser.BookmarkColumns.BOOKMARK, 1);
// map.put(Browser.BookmarkColumns.THUMBNAIL, bitmapToBytes(thumbnail));
cr.update(Browser.BOOKMARKS_URI, map, "_id = " + cursor.getInt(0), null);
} else {
int count = cursor.getCount();
boolean matchedTitle = false;
for (int i = 0; i < count; i++) {
// One or more bookmarks already exist for this site.
// Check the names of each
cursor.moveToPosition(i);
if (cursor.getString(Browser.HISTORY_PROJECTION_TITLE_INDEX).equals(name)) {
// The old bookmark has the same name.
// Update its creation time.
map.put(Browser.BookmarkColumns.CREATED, creationTime);
cr.update(Browser.BOOKMARKS_URI, map, "_id = " + cursor.getInt(0), null);
matchedTitle = true;
break;
}
}
if (!matchedTitle) {
// Adding a bookmark for a site the user has visited,
// or a new bookmark (with a different name) for a site
// the user has visited
map.put(Browser.BookmarkColumns.TITLE, name);
map.put(Browser.BookmarkColumns.URL, url);
map.put(Browser.BookmarkColumns.CREATED, creationTime);
map.put(Browser.BookmarkColumns.BOOKMARK, 1);
map.put(Browser.BookmarkColumns.DATE, 0);
// map.put(Browser.BookmarkColumns.THUMBNAIL, bitmapToBytes(thumbnail));
int visits = 0;
if (count > 0) {
// The user has already bookmarked, and possibly
// visited this site. However, they are creating
// a new bookmark with the same url but a different
// name. The new bookmark should have the same
// number of visits as the already created bookmark.
visits = cursor.getInt(Browser.HISTORY_PROJECTION_VISITS_INDEX);
}
// Bookmark starts with 3 extra visits so that it will
// bubble up in the most visited and goto search box
map.put(Browser.BookmarkColumns.VISITS, visits + 3);
cr.insert(Browser.BOOKMARKS_URI, map);
}
}
if (retainIcon) {
WebIconDatabase.getInstance().retainIconForPageUrl(url);
}
cursor.close();
}

Categories

Resources