Choose specific contacts and add to application listview - android

I want to read all contacts and use those in my application. i read all related topics but my implementation is very ِdifferent...
i want to Achieve this form :
see Image
1-user can choose specific contacts
2- Theirs information must add in application listview
3-and user can Choose silent/Normal status for contacts that he choosen.
How i can get contact based on this scenario ?

use explicit intent and startActivityForResult() for getting contacts
static final int PICK_CONTACT_REQUEST = 1; // The request code
...
private void pickContact() {
Intent pickContactIntent = new Intent(Intent.ACTION_PICK, Uri.parse("content://contacts"));
pickContactIntent.setType(Phone.CONTENT_TYPE); // Show user only contacts w/ phone numbers
startActivityForResult(pickContactIntent, PICK_CONTACT_REQUEST);
}
===============================
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
// Check which request it is that we're responding to
if (requestCode == PICK_CONTACT_REQUEST) {
// Make sure the request was successful
if (resultCode == RESULT_OK) {
// Get the URI that points to the selected contact
Uri contactUri = data.getData();
// We only need the NUMBER column, because there will be only one row in the result
String[] projection = {Phone.NUMBER};
// Perform the query on the contact to get the NUMBER column
// We don't need a selection or sort order (there's only one result for the given URI)
// CAUTION: The query() method should be called from a separate thread to avoid blocking
// your app's UI thread. (For simplicity of the sample, this code doesn't do that.)
// Consider using CursorLoader to perform the query.
Cursor cursor = getContentResolver()
.query(contactUri, projection, null, null, null);
cursor.moveToFirst();
// Retrieve the phone number from the NUMBER column
int column = cursor.getColumnIndex(Phone.NUMBER);
String number = cursor.getString(column);
// Do something with the phone number...
}
}
}
Then add details to your applications listview.do as you need to

Don't know if you figure this out after a year but here's step 1:
private static final int CONTACT_PICKER_RESULT = 1001;
...
public void methodname() {
// By using ContactsContract.CommonDataKinds.Phone.CONTENT_URI, the user is
// presented with a list of contacts, with one entry per phone number.
// The selected contact is guaranteed to have a name and phone number.
Intent contactPickerIntent = new Intent(Intent.ACTION_PICK, ContactsContract.CommonDataKinds.Phone.CONTENT_URI);
startActivityForResult(contactPickerIntent, CONTACT_PICKER_RESULT);
return true;
}

Related

Obtaining Email Addresses of Specific Contact Without Permissions

I can easily get a list of every email address for every Contact using the following example snippets:
//...
private val getPerson = registerForActivityResult(PickContact()) {
it?.also { contactUri ->
val personDetails = ContactForPerson("", "", "")
val projection = arrayOf(
ContactsContract.CommonDataKinds.Phone.LOOKUP_KEY, //String
ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME_PRIMARY,//String
ContactsContract.CommonDataKinds.Email.ADDRESS, //String
)
context?.contentResolver?.query(contactUri, projection, null, null, null)?.apply {
moveToFirst()
personDetails.apply {
uri = getStringOrNull(0)
name = getString(1)
email = getStringOrNull(2)
}
close()
}
}
}
//...
fab.setOnClickListener {
//...
getPerson.launch(0)
//...
}
//...
class PickContact : ActivityResultContract<Int, Uri?>() {
override fun createIntent(context: Context, input: Int?) =
Intent(Intent.ACTION_PICK, ContactsContract.Contacts.CONTENT_URI).also {
it.type = ContactsContract.CommonDataKinds.Email.CONTENT_TYPE
}
override fun parseResult(resultCode: Int, intent: Intent?): Uri? =
if (resultCode == RESULT_OK) intent?.data else null
}
The question is, since I already have some information about a Contact, is there a way for me to filter the giant list of every email address for every Contact to only show me the email addresses for a single Contact?
I noticed Get specific contact information from URI returned from Intent.ACTION_PICK, but the information is rather dated and it's not clear if the READ_CONTACTS permission is required, which is not desired.
Thank you.
It seems you're calling an EMAIL-PICKER and not a CONTACT-PICKER, by setting the intent type to Email.CONTENT_TYPE.
This means the user will be choosing a specific email in the device's default contacts app.
The result you're then getting from the picker is not a contactUri, rather a dataUri - i.e. a uri that points to a specific row in the Data table, which only allows you to get info about that specific row, in this case it must be an email row.
This also means your projection is a bit funny by using fields under CommonDataKinds.Phone.X, this doesn't matter too much as these fields are inherited from Data.CONTENT_URI, but to prevent confusion you should probably replace these with:
Data.LOOKUP_KEY,
Data.DISPLAY_NAME_PRIMARY,
Email.ADDRESS,
Now, if you want all the contact's email rather then a single one, you should not set the intent type - this will launch a contact picker which will allow you to get the contact's emails + phones + name by retrieving the Entity as shown here.

Get Android contacts with type-to-filter functionality, restricted to a specific account

I'm trying to:
Display a list of contacts
Let the user search through them by typing a query
Limit search results only to a specific Google/Gmail account.
This is how I build the URI for the cursor:
// User is searching for 'jo'
String query = "jo";
Uri uri = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI, Uri.encode(query));
// Restrict the query to contacts from 'example#gmail.com'
Uri.Builder builder = uri.buildUpon();
builder.appendQueryParameter(
ContactsContract.DIRECTORY_PARAM_KEY, String.valueOf(ContactsContract.Directory.DEFAULT));
builder.appendQueryParameter(ContactsContract.RawContacts.ACCOUNT_NAME, "example#gmail.com");
builder.appendQueryParameter(ContactsContract.RawContacts.ACCOUNT_TYPE, "com.google");
uri = builder.build();
This is the final URI:
content://com.android.contacts/contacts/filter/jo?directory=0&account_name=example%40gmail.com&account_type=com.google
Currently, this shows search results from all accounts on the phone.
NOTE: If I use Contacts.CONTENT_URI instead of Contacts.CONTENT_FILTER_URI, then specifying the directory/account works as expected, but I can no longer use 'type-to-filter' style search.
The documentation does state:
The most important use case for Directories is search. A Directory
provider is expected to support at least Contacts.CONTENT_FILTER_URI.
Could anyone help point out what I might be doing wrong?
I added your code in Google's example for contact retrieving, and with a couple of changes it worked perfectly with my Google for Work account.
The changes I made were:
remove the line with DIRECTORY_PARAM_KEY, as I didn't find it to make any difference
removed ContactsQuery.SELECTION from the return statement, because that constant prevents "invisible" contacts from being displayed.
The changes were made to ContactsListFragment.java
#Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
// If this is the loader for finding contacts in the Contacts Provider
// (the only one supported)
if (id == ContactsQuery.QUERY_ID) {
Uri contentUri;
// There are two types of searches, one which displays all contacts and
// one which filters contacts by a search query. If mSearchTerm is set
// then a search query has been entered and the latter should be used.
if (mSearchTerm == null) {
// Since there's no search string, use the content URI that searches the entire
// Contacts table
contentUri = ContactsQuery.CONTENT_URI;
} else {
// Since there's a search string, use the special content Uri that searches the
// Contacts table. The URI consists of a base Uri and the search string.
contentUri = Uri.withAppendedPath(ContactsQuery.FILTER_URI, Uri.encode(mSearchTerm));
}
// HERE COMES YOUR CODE (except the DIRECTORY_PARAM_KEY line)
Uri.Builder builder = contentUri.buildUpon();
builder.appendQueryParameter(ContactsContract.RawContacts.ACCOUNT_NAME, "example#mycompany.com");
builder.appendQueryParameter(ContactsContract.RawContacts.ACCOUNT_TYPE, "com.google");
contentUri = builder.build();
// Returns a new CursorLoader for querying the Contacts table. No arguments are used
// for the selection clause. The search string is either encoded onto the content URI,
// or no contacts search string is used. The other search criteria are constants. See
// the ContactsQuery interface.
return new CursorLoader(getActivity(),
contentUri,
ContactsQuery.PROJECTION,
null, // I REMOVED SELECTION HERE
null,
ContactsQuery.SORT_ORDER);
}
Log.e(TAG, "onCreateLoader - incorrect ID provided (" + id + ")");
return null;
}

How to programmatically open contacts pick with search filter entered programmatically?

I want to open Contacts pick activity from my application with search field should be filled programmatically.
Can anyone suggest what URI shoud i use or anything to put in intent's extra?
private static final int PICK_CONTACT_SUBACTIVITY = 2;
private void startContactActivity() {
Uri uri = Uri.parse("content://contacts/people");
// Here in this normally we pass number e.g. Uri.encode("987") but i want to pass name as filter is it possible?
// I have also tried
//uri = Uri.withAppendedPath(android.provider.ContactsContract.Contacts.CONTENT_FILTER_URI, Uri.encode("pra"));
//uri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, Uri.encode("pra"));
uri = Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_FILTER_URI, Uri.encode("pra"));
Intent intent = new Intent(Intent.ACTION_PICK, uri);
startActivityForResult(intent, PICK_CONTACT_SUBACTIVITY);
}
Can anyone suggest how can i achieve this?
You can follow :
how-to-pick-contact-number-from-phone-book-of-android-in-to-my-application
or
developer.android.com/training/contacts-provider/modify-data
It seems that it is not possible to specify a filter programmatically.
The Android SDK documentation states (in the chapter "Retrieval and modification with intents") that for ACTION_PICK you can only use one of
Contacts.CONTENT_URI, Phone.CONTENT_URI, StructuredPostal.CONTENT_URI, Email.CONTENT_URI. This is indirectly a filter (all contacts, all with phone numbers, all with postal address, or all with email), but it is limited to this.

Android intent to call a contact, not a number

Context:
I wrote a small easy dialer for android which dials telephone numbers
for contacts.
I use Intent.ACTION_CALL and pass in "tel:" for contacts with just one tel number or with a preferred default number
Within the app I have the contact's lookup_key so that I can access the contact
Question:
I want to initiate a call to a Contact not to a number so that Android:
if contact has 2+ numbers: will fire up a phone number selection dialog and then initiate the call
if the contact has just 1 number: just initiate the call
I could of course implement a popup from scratch but I'd prefer to delegate to a standard action so that the user has the very same UX as using the standard dialer.
You can use something like this to prompt the user to choose the contact, then which phone number to call (if there is more than one)... than pass that to the intent to make the call:
Intent intent = new Intent(Intent.ACTION_PICK, Contacts.CONTENT_URI);
intent.setType(ContactsContract.CommonDataKinds.Phone.CONTENT_TYPE);
startActivityForResult(intent, 1);
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == RESULT_OK) {
Uri contactData = data.getData();
String theID = contactData.toString());
//MAKE YOUR CALL .. do whatever... example:
ContentResolver contentResolver = getContentResolver();
Uri contactData = Uri.parse(theID);
Cursor cur = contentResolver.query(contactData, null, null, null, null);
String theNumber = cur.getString(cur.getColumnIndex("data4"));
cur.close();
Intent my_callIntent = new Intent(Intent.ACTION_CALL);
my_callIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK );
my_callIntent.setData(Uri.parse("tel:" + theNumber));
startActivity(my_callIntent);
}
}
Its not pretty or perfect, probably needs some modifications, just kinda going off the top of my head but hopefully you get the idea.

Get Selected Image File Location in Android

I am currently making an app which works with images. I need to implement functionality where the user picks a file stored on the SD card. Once they pick the picture (using the Android gallery), the the file-location of the image will be sent to another Activity, where other work will be done upon it.
I have seen similar posts here on SO, but none to answer my question specifically. Basically this is the code I am doing when the user clicks the "Load a Picture" button:
// Create a new Intent to open the picture selector:
Intent loadPicture = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
// To start it, run the startActivityForResult() method:
startActivityForResult(loadPicture, SELECT_IMAGE);
From that code, I then have a onActivityResult() method to listen to the call-back:
// If the user tried to select an image:
if(requestCode == SELECT_IMAGE)
{
// Check if the user actually selected an image:
if(resultCode == Activity.RESULT_OK)
{
// This gets the URI of the image the user selected:
Uri selectedImage = data.getData();
// Create a new Intent to send to the next Activity:
Intent i = new Intent(currentActivty.this, nextActivity.class);
// ----------------- Problem Area -----------------
// I would like to send the filename to the Intent object, and send it over.
// However, the selectedImage.toString() method will return a
// "content://" string instead of a file location. How do I get a file
// location from that URI object?
i.putExtra("PICTURE_LOCATION", selectedImage.toString());
// Start the activity outlined with the Intent above:
startActivity(i);
As the code above states, the uri.toString() will return a content:// string instead of the file location of the selected picture. How do I obtain the file location?
Note: Another possible solution is to send over the content:// string and convert that into a Bitmap (which is what happens in the next Activity). However, I don't know how to do that.
I have found the answer to my own question. After doing some more searching, I finally stumbled upon a post here on SO which asks the same question here: android get real path by Uri.getPath().
Unfortunately, the answer has a broken link. After some Google searching, I found the correct link to the site here: http://www.androidsnippets.org/snippets/130/ (I have verified that this code does indeed work.)
However, I decided to take a different route. Since my next Activity is using an ImageView to display the picture, I am instead going to use the Uri content string for all methods that link to the next Activity.
In the next Activity, I am using the ImageView.setImageUri() method.
Here is the code I am doing in the next Activity to display the picture from the content:// string:
// Get the content string from the previous Activity:
picLocation = getIntent().getStringExtra("PICTURE_LOCATION");
// Instantiate the ImageView object:
ImageView imageViewer = (ImageView)findViewById(R.id.ImageViewer);
// Convert the Uri string into a usable Uri:
Uri temp = Uri.parse(picLocation);
imageViewer.setImageURI(temp);
I hope that this question and answer will be helpful to future Android developers.
Here's another answer that I hope someone finds useful:
You can do this for any content in the MediaStore. In my app, I have to get the path from URIs and get the URI from paths. The former:
/**
* Gets the corresponding path to a file from the given content:// URI
* #param selectedVideoUri The content:// URI to find the file path from
* #param contentResolver The content resolver to use to perform the query.
* #return the file path as a string
*/
private String getFilePathFromContentUri(Uri selectedVideoUri,
ContentResolver contentResolver) {
String filePath;
String[] filePathColumn = {MediaColumns.DATA};
Cursor cursor = contentResolver.query(selectedVideoUri, filePathColumn, null, null, null);
cursor.moveToFirst();
int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
filePath = cursor.getString(columnIndex);
cursor.close();
return filePath;
}
The latter (which I do for videos, but can also be used for Audio or Files or other types of stored content by substituting MediaStore.Audio (etc) for MediaStore.Video:
/**
* Gets the MediaStore video ID of a given file on external storage
* #param filePath The path (on external storage) of the file to resolve the ID of
* #param contentResolver The content resolver to use to perform the query.
* #return the video ID as a long
*/
private long getVideoIdFromFilePath(String filePath,
ContentResolver contentResolver) {
long videoId;
Log.d(TAG,"Loading file " + filePath);
// This returns us content://media/external/videos/media (or something like that)
// I pass in "external" because that's the MediaStore's name for the external
// storage on my device (the other possibility is "internal")
Uri videosUri = MediaStore.Video.Media.getContentUri("external");
Log.d(TAG,"videosUri = " + videosUri.toString());
String[] projection = {MediaStore.Video.VideoColumns._ID};
// TODO This will break if we have no matching item in the MediaStore.
Cursor cursor = contentResolver.query(videosUri, projection, MediaStore.Video.VideoColumns.DATA + " LIKE ?", new String[] { filePath }, null);
cursor.moveToFirst();
int columnIndex = cursor.getColumnIndex(projection[0]);
videoId = cursor.getLong(columnIndex);
Log.d(TAG,"Video ID is " + videoId);
cursor.close();
return videoId;
}
Basically, the DATA column of MediaStore (or whichever sub-section of it you're querying) stores the file path, so you use what you know to look up the DATA, or you query on the DATA field to select the content you care about.

Categories

Resources