The following code gets me image thumbnails from local pictures on the phone/sd cards:
public Task<List<Album>> GetAllAlbumsAndPhotos(object activity)
{
Activity activ = activity as Activity;
List<Album> albums = new List<Album>();
// which image properties are we querying
String[] projection = new String[]
{
MediaStore.Images.Media.InterfaceConsts.BucketId,
MediaStore.Images.Media.InterfaceConsts.BucketDisplayName,
MediaStore.Images.Media.InterfaceConsts.DateTaken,
MediaStore.Images.Media.InterfaceConsts.DateAdded,
MediaStore.Images.Media.InterfaceConsts.Data
};
// Get the base URI for the People table in the Contacts content provider.
AndroidNet.Uri images = MediaStore.Images.Media.ExternalContentUri;
// Make the query.
var cursor = activ.ContentResolver.Query(images,
projection, // Which columns to return
"", // Which rows to return (all rows)
null, // Selection arguments (none)
"" // Ordering
);
if (cursor.MoveToFirst())
{
int bucketColumn = cursor.GetColumnIndex(MediaStore.Images.Media.InterfaceConsts.BucketDisplayName);
int takenColumn = cursor.GetColumnIndex(MediaStore.Images.Media.InterfaceConsts.DateTaken);
int addedColumn = cursor.GetColumnIndex(MediaStore.Images.Media.InterfaceConsts.DateAdded);
int dataColumn = cursor.GetColumnIndex(MediaStore.Images.Media.InterfaceConsts.Data);
do
{
.
.
.
} while (cursor.MoveToNext());
}
return Task.FromResult(albums);
}
How do I include Video thumbnails? Can It be done with the same code or does it have to be done independently from this block of code?
Related
I have an app that reads the contact details of the phone. This code returns 744 as the id of a particular contact's row when accessed through Email.ContentUri.
var uriEmail = ContactsContract.CommonDataKinds.Email.ContentUri;
string[] projectionEmail = { ContactsContract.Contacts.InterfaceConsts.Id, ContactsContract.Contacts.InterfaceConsts.DisplayName, ContactsContract.Contacts.InterfaceConsts.PhotoUri, ContactsContract.CommonDataKinds.Email.Address };
var cursorEmail = this.Activity.ContentResolver.Query(uriEmail, projectionEmail, null, null, null);
// var contactList = new List<string>();
contacts = new ObservableCollection<Contact>();
if (cursorEmail.MoveToFirst())
{
do
{
//contactList.Add(cursor.GetString(cursor.GetColumnIndex(projection[2])));
contacts.Add(new Contact()
{
Id = cursorEmail.GetInt(cursorEmail.GetColumnIndex(projectionEmail[0])),
Name = cursorEmail.GetString(cursorEmail.GetColumnIndex(projectionEmail[1])),
Photo = cursorEmail.GetString(cursorEmail.GetColumnIndex(projectionEmail[2])),
Email = cursorEmail.GetString(cursorEmail.GetColumnIndex(projectionEmail[3])),
});
}
while (cursorEmail.MoveToNext());
}
ListView listEmail = v.FindViewById<ListView>(Resource.Id.listViewSelect);
listEmail.Adapter = new ContactAdapter(v.Context, contacts);
listEmail.ItemClick += OnClientListClick;
This code returns 752 as the id of the same contact when accessed through StructuredPostal.ContentUri.
var uriAddress = ContactsContract.CommonDataKinds.StructuredPostal.ContentUri;
string[] projectionAddress = { ContactsContract.Contacts.InterfaceConsts.Id, ContactsContract.Contacts.InterfaceConsts.DisplayName, ContactsContract.Contacts.InterfaceConsts.PhotoUri, ContactsContract.CommonDataKinds.StructuredPostal.Street, ContactsContract.CommonDataKinds.StructuredPostal.Postcode };
var cursorAddress = this.Activity.ContentResolver.Query(uriAddress, projectionAddress, null, null, null);
// var contactList = new List<string>();
properties = new ObservableCollection<Property>();
if (cursorAddress.MoveToFirst())
{
do
{
int n = cursorAddress.GetInt(cursorAddress.GetColumnIndex(projectionAddress[0]));
string str = cursorAddress.GetString(cursorAddress.GetColumnIndex(projectionAddress[1]));
if (n == nId)
{
//contactList.Add(cursor.GetString(cursor.GetColumnIndex(projection[2])));
properties.Add(new Property()
{
Id = cursorAddress.GetInt(cursorAddress.GetColumnIndex(projectionAddress[0])),
Name = cursorAddress.GetString(cursorAddress.GetColumnIndex(projectionAddress[1])),
Photo = cursorAddress.GetString(cursorAddress.GetColumnIndex(projectionAddress[2])),
Street = cursorAddress.GetString(cursorAddress.GetColumnIndex(projectionAddress[3])),
Postcode = cursorAddress.GetString(cursorAddress.GetColumnIndex(projectionAddress[4])),
});
}
}
while (cursorAddress.MoveToNext());
}
ListView listAddress = v.FindViewById<ListView>(Resource.Id.listViewSelect);
listAddress.Adapter = new PropertyAdapter(v.Context, properties);
listAddress.ItemClick += OnPropertyListClick;
Is there a unique identifier that's allocated to the contact in the Android phone?
If you wanna a unique id, you could use CONTACT_ID which is a reference to _ID of each contact.
CONTACT_ID:
https://developer.android.com/reference/android/provider/ContactsContract.RawContactsColumns.html#CONTACT_ID
_ID:https://developer.android.com/reference/android/provider/BaseColumns#_ID
If you want to use the unique id cross device, you could try to use the LOOKUP_KEY.
LOOKUP_KEY:
https://developer.android.google.cn/reference/android/provider/ContactsContract.ContactsColumns.html#LOOKUP_KEY
For more code details, you could check the link below. Get cross-device unique ID for Android phone contacts
I am trying to store and retrieve image data in Sqlite Db.
To do so I firstly stored in local device memory an example pic (path: storage/emulated/0/Download/).
public class MainActivity extends AppCompatActivity implements LoaderManager.LoaderCallbacks<Cursor> {
private final String SAMPLE_IMAGE_PATH = "/storage/emulated/0/Download/image.jpg";
Then I set up an insert method to feed the db with these example data:
private void insertProduct() {
// Create a ContentValues object where column names are the keys,
// and sample attributes are the values.
ContentValues values = new ContentValues();
values.put(InventoryContract.ProductEntry.COLUMN_PRODUCT_NAME, sampleName);
values.put(InventoryContract.ProductEntry.COLUMN_PRODUCT_QTY, sampleQty);
values.put(InventoryContract.ProductEntry.COLUMN_PRODUCT_PRICE, SamplePrice);
values.put(InventoryContract.ProductEntry.COLUMN_EMAIL, sampleMail);
values.put(InventoryContract.ProductEntry.COLUMN_PHONE, samplePhone);
values.put(InventoryContract.ProductEntry.COLUMN_PRODUCT_PIC, SAMPLE_IMAGE_PATH);
//insert a new row
Uri newUri = getContentResolver().insert(InventoryContract.ProductEntry.CONTENT_URI,values);
}
and I define the onCreateLoader method as follows:
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
// Define a projection that specifies the columns from the table we care about.
String[] projection = {
InventoryContract.ProductEntry._ID,
InventoryContract.ProductEntry.COLUMN_PRODUCT_PIC,
InventoryContract.ProductEntry.COLUMN_PRODUCT_PRICE,
InventoryContract.ProductEntry.COLUMN_PRODUCT_QTY,
InventoryContract.ProductEntry.COLUMN_PRODUCT_NAME};
// This loader will execute the ContentProvider's query method on a background thread
return new CursorLoader(this,
InventoryContract.ProductEntry.CONTENT_URI,
projection,
null,
null,
null);
}
In the CursorAdapter class I updated the listView adding the data from db in bindView() method:
public void bindView(View view, Context context, Cursor cursor) {
// Find individual views that we want to modify in the list item layout
TextView nameTextView = (TextView) view.findViewById(R.id.prod_name);
TextView priceTextView = (TextView) view.findViewById(R.id.prod_price);
TextView qtyTextView = (TextView) view.findViewById(R.id.prod_qty);
ImageView prodImageView = (ImageView) view.findViewById(R.id.prod_img);
// Find the columns of attributes that we're interested in
int nameColumnIndex = cursor.getColumnIndex(InventoryContract.ProductEntry.COLUMN_PRODUCT_NAME);
int priceColumnIndex = cursor.getColumnIndex(InventoryContract.ProductEntry.COLUMN_PRODUCT_PRICE);
int qtyColumnIndex = cursor.getColumnIndex(InventoryContract.ProductEntry.COLUMN_PRODUCT_QTY);
int picColumnIndex = cursor.getColumnIndex(InventoryContract.ProductEntry.COLUMN_PRODUCT_PIC);
// Read the attributes from the Cursor for the current product
String prodName = cursor.getString(nameColumnIndex);
Double prodPrice = cursor.getDouble(priceColumnIndex);
int prodQty = cursor.getInt(qtyColumnIndex);
byte [] prodImg = cursor.getBlob(picColumnIndex);
BitmapFactory.Options options = new BitmapFactory.Options();
options.inTempStorage = new byte[1024 * 32];
Bitmap bmp = BitmapFactory.decodeByteArray(prodImg, 0, prodImg.length, options);
//Update Views
nameTextView.setText(String.valueOf(prodName));
priceTextView.setText(prodPrice.toString());
qtyTextView.setText(String.valueOf(prodQty));
prodImageView.setImageBitmap(bmp);
}
}
When I try execute this code everything goes ok, but I see a blank image instead of both the selected pic and placer pic.
So I think that there is some problem with inserting data into db.
I am trying to store and retrieve image data in Sqlite Db
I do not recommend this. Store the images in files. Store data in the rows that identifies the files.
Then I set up an insert method to feed the db with these example data
You are storing a string in COLUMN_PRODUCT_PIC. You are not storing a byte[]. This is good, relative to my recommendation. This is bad relative to your data-retrieval code, where you are attempting to retrieve a byte[].
I want to load several contacts via Xamarin.Contacts.AddressBook, at the moment I have something like:
var loookupIDs = /* load 10 saved contact IDs */
var addressBook = new AddressBook(context) { PreferContactAggregation = true };
foreach(var id in loookupIDs)
{
var contact = addressBook.Load(id);
names.Add(contact.DisplayName);
}
However, this is really slow (tested on Android device) - even just loading 10 contacts. Is there a way to batch up the loading so it's faster? Or is the only option to use platform specific APIs instead of the Xamarin wrapper.
Yes, Xamarin.Mobile is kind of slow. It combines all possible contacts (phones, mails, etc) and all possible fields, which is not recommended by Android reference manual.
I recommend you to use native way to query your contacts with Cursor and filter it for your needs. Sadly, Xamarin dev mixed up all constants, so it is not trivial task.
Here is complete example
public class PhoneContactInfo
{
public string PhoneContactID { get; set; }
public string ContactName { get; set; }
public string ContactNumber { get; set; }
}
public IEnumerable<PhoneContactInfo> GetAllPhoneContacts(IEnumerable<int> filterIds = null)
{
Log.Debug("GetAllPhoneContacts", "Getting all Contacts");
var arrContacts = new System.Collections.Generic.List<PhoneContactInfo>();
PhoneContactInfo phoneContactInfo = null;
var uri = ContactsContract.CommonDataKinds.Phone.ContentUri;
string[] projection = { ContactsContract.Contacts.InterfaceConsts.Id,
ContactsContract.Contacts.InterfaceConsts.DisplayName,
ContactsContract.CommonDataKinds.Phone.Number
};
//String[] strings = filterIds.Select(k => Convert.ToString(k)).ToArray();
//string whereClause = ContactsContract.Contacts.InterfaceConsts.Id + " = ? ";
var cursor = MainActivity.ContextHolder.ContentResolver.Query(uri, projection,
null,
null,
null);
cursor.MoveToFirst();
while (cursor.IsAfterLast == false)
{
int phoneContactID = cursor.GetInt(cursor.GetColumnIndex(ContactsContract.Contacts.InterfaceConsts.Id));
if (filterIds.Contains(phoneContactID))
{
String contactNumber = cursor.GetString(cursor.GetColumnIndex(ContactsContract.CommonDataKinds.Phone.Number));
String contactName = cursor.GetString(cursor.GetColumnIndex(ContactsContract.Contacts.InterfaceConsts.DisplayName));
phoneContactInfo = new PhoneContactInfo()
{
PhoneContactID = Convert.ToString(phoneContactID),
ContactName = contactName,
ContactNumber = contactNumber
};
arrContacts.Add(phoneContactInfo);
}
cursor.MoveToNext();
}
cursor.Close();
cursor = null;
Log.Debug("GetAllPhoneContacts", "Got all Contacts");
return arrContacts;
}
If you wish to add some fancy async
public Task<IEnumerable<PhoneContactInfo>> GetAllPhoneContactsAsync(IEnumerable<int> filterIds)
{
return Task.FromResult(GetAllPhoneContacts(filterIds));
}
Also take a look at commented whereClause. You possibly can construct 'SQL like' where clause to make this query even more faster. Just build a string with several '=' and 'or'
P.S.
I didn't measure performance differences, if anyone has decent statistics i will be grateful
It looks like you access AdressBook for each loookupID, this might cause your speed issue.
Try:
1) Fetch all contacts, or only those you might be interested in. (Use Linq)
2) Do further work with found contacts
Example from Xamarin docs:
http://blog.xamarin.com/introducing-xamarin-contacts/
var book = new AddressBook (this) {
PreferContactAggregation = true
};
foreach (Contact c in book.Where (c => c.LastName == "Smith")) {
print (c.DisplayName);
foreach (Phone p in c.Phones)
print ("Phone: " + p.Number);
foreach (Email e in c.Emails)
print ("Email: " + e.Address);
}
I have created a Project having many activities. One activity is to record the video, that is working fine. I can see the recorded video in my specified folder without restart my tablet.
But when I try to find all the videos in that folder in some other activity using query, see code below. Then I can't see my recorded video until I restart my tablet. I can see just old recorded videos before starting my tablet. I couldn't understand this strange behavior.
Can anyone put some light on this issue??
Thanks.
private void initVideosId() { // getting the videos id in Video Folder of SD Card
try {
// Here we set up a string array of the thumbnail ID column we want
// to get back
String[] proj = { _ID };
//Querying for the videos in VideoGallery folder of SD card
// Now we create the cursor pointing to the external thumbnail store
_cursor = managedQuery(_contentUri, proj, // Which columns to return
MEDIA_DATA + " like ? ", // WHERE clause; which rows to
// return (all rows)
new String[] { "%VideoGallery%" }, // WHERE clause selection
// arguments (none)
null); // Order-by clause (ascending by name)
int count = _cursor.getCount();
// We now get the column index of the thumbnail id
_columnIndex = _cursor.getColumnIndex(_ID);
// initialize
_videosId = new int[count];
// move position to first element
_cursor.moveToFirst();
for (int i = 0; i < count; i++) {
int id = _cursor.getInt(_columnIndex);
//
_videosId[i] = id;
//
_cursor.moveToNext();
//
}
} catch (Exception ex) {
showToast(ex.getMessage().toString());
}
}
If you stored the file on external storage, you need to use MediaScannerConnection to get the MediaStore to index that file, such as:
MediaScannerConnection.scanFile(
this,
new String[] {file.getAbsolutePath()},
null,
new OnScanCompletedListener() {
#Override
public void onScanCompleted(String path, Uri uri) {
// do something if you want
}
});
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!