I need to fetch out the list of contacts that are recently used in last 24 hours and most frequently used.
I have searched a lot but did not find any way to do that. I also come to know that google has revoked the URIs to get frequently used contacts : https://developer.android.com/reference/android/provider/ContactsContract.Contacts#CONTENT_FREQUENT_URI
But what is the substitute of this URI is not given?
Please let me know the ways to achieve:
Fetch list of contacts contacted recently in last 24 hours.
Fetch the top 3 most frequently used contacts.
The whole point of deprecating the CONTENT_FREQUENT_URI as well as the TIMES_CONTACTED and LAST_TIME_CONTACTED fields in the Contacts table are to prevent apps from accessing the information you're looking for.
Google now considers this info to be sensitive user info, and will not allow apps to obtain that going forward.
However, from my experience, it seems that all devices I know of or are used by our users still allow access to the deprecated API, so if you need something that will be ok for most of your users within the next year or so, you can still use it.
Code should be something like:
String[] projection = new String[] { Contacts._ID, Contacts.DISPLAY_NAME, Contacts.LAST_TIME_CONTACTED };
Cursor lastContacted = getContentResolver().query(Contacts.CONTENT_URI, projection, Contacts.LAST_TIME_CONTACTED + " < " + lastDayTimestamp, null, Contacts.LAST_TIME_CONTACTED + " DESC");
DatabaseUtils.dumpCursor(lastContacted);
Cursor mostContacted = getContentResolver().query(Contacts.CONTENT_URI, projection, null, null, Contacts.TIMES_CONTACTED + " DESC");
DatabaseUtils.dumpCursor(mostContacted); // might want to limit this to 3
public class MainActivity extends AppCompatActivity {
ListView listView ;
ArrayList<String> StoreContacts ;
ArrayAdapter<String> arrayAdapter ;
Cursor cursor ;
String name, phonenumber ;
public static final int RequestPermissionCode = 1 ;
Button button;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
listView = (ListView)findViewById(R.id.listview1);
button = (Button)findViewById(R.id.button1);
StoreContacts = new ArrayList<String>();
EnableRuntimePermission();
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
GetContactsIntoArrayList();
arrayAdapter = new ArrayAdapter<String>(
MainActivity.this,
R.layout.contact_items_listview,
R.id.textView, StoreContacts
);
listView.setAdapter(arrayAdapter);
}
});
}
public void GetContactsIntoArrayList(){
cursor =
getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
null,null, null, null);
while (cursor.moveToNext()) {
name =
cursor.getString(cursor.getColumnIndex
(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAM
E));
phonenumber =
cursor.getString(cursor.getColumnIndex
(ContactsContract.CommonDataKinds.Phone.NUMBER));
StoreContacts.add(name + " " + ":" + " " + phonenumber);
}
cursor.close();
}
public void EnableRuntimePermission(){
if (ActivityCompat.shouldShowRequestPermissionRationale(
MainActivity.this,
Manifest.permission.READ_CONTACTS))
{
Toast.makeText(MainActivity.this,"CONTACTS permission allows us to Access
CONTACTS app", Toast.LENGTH_LONG).show();
} else {
ActivityCompat.requestPermissions(MainActivity.this,new String[]{
Manifest.permission.READ_CONTACTS}, RequestPermissionCode);
}
}
#Override
public void onRequestPermissionsResult(int RC, String per[], int[] PResult) {
switch (RC) {
case RequestPermissionCode:
if (PResult.length > 0 && PResult[0] ==
PackageManager.PERMISSION_GRANTED) {
Toast.makeText(MainActivity.this,"Permission Granted, Now your
application can access CONTACTS.", Toast.LENGTH_LONG).show();
} else {
Toast.makeText(MainActivity.this,"Permission Canceled, Now your
application cannot access CONTACTS.", Toast.LENGTH_LONG).show();
}
break;
}
}
}
Related
I am trying to edit a group title and Notes,
Editing title works for both system groups and user created groups,
Although notes column only persist if it is a System group(e.g. "Contacts", "Friends", "Family", "Coworkers"),
I assume that it either doesn't save notes for user created groups or some how gets overwritten with title column content in notes column.
How can I use notes column in contact groups? is there any other way to store additional information with groups?
Here is my code snippet:
ArrayList<ContentProviderOperation> ops =new ArrayList<ContentProviderOperation>();
ContentProviderOperation.Builder op =
ContentProviderOperation.newUpdate(ContactsContract.Groups.CONTENT_URI)
.withSelection(ContactsContract.Groups._ID + "="+group.getId(), null)
.withValue(ContactsContract.Groups.TITLE, group.getTitle());
HashMap<String, String> notes = group.getNotes();
if(notes!=null && notes.size()>0){
op = op.withValue(ContactsContract.Groups.NOTES, new Gson().toJson(group.getNotes()));
}
ops.add(op.build());
try {
getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops);
} catch (RemoteException e) {
e.printStackTrace();
} catch (OperationApplicationException e) {
e.printStackTrace();
}
Hope this solution works for you, seems to be working for me.
I've used ContentResolver.update() method.
I assume that it either doesn't save notes for user created groups or some how gets overwritten with title column content in notes column.
I was able to update the notes for user created groups using below code.
How can I use notes column in contact groups?
You can use notes column to save any TEXT value because it's defined of type TEXT in sqlite. See ContactsContract.Groups.NOTES .
(Tested on Google Pixel XL, Oreo 8.0.0)
public class MainActivity extends AppCompatActivity {
private Cursor mCursor;
private SimpleCursorAdapter adapter;
private ListView lvGroups;
#Override
protected void onDestroy() {
if (mCursor != null)
mCursor.close();
super.onDestroy();
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
lvGroups = findViewById(R.id.lvGroups);
checkAndRequestPermission();
}
private void checkAndRequestPermission() {
if (PermissionChecker.checkSelfPermission(this, Manifest.permission.READ_CONTACTS) == PermissionChecker.PERMISSION_GRANTED) {
loadGroups();
} else {
ActivityCompat.requestPermissions(this, new String[] {Manifest.permission.READ_CONTACTS, Manifest.permission.WRITE_CONTACTS}, 123);
}
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
boolean isGranted = true;
for (int i = 0; i < grantResults.length; i++) {
if (grantResults[i] == PermissionChecker.PERMISSION_DENIED)
isGranted = false;
}
if (isGranted)
loadGroups();
else
ActivityCompat.requestPermissions(this, new String[] {Manifest.permission.READ_CONTACTS, Manifest.permission.WRITE_CONTACTS},123);
}
private void loadGroups() {
mCursor = getContentResolver().query(ContactsContract.Groups.CONTENT_URI,null,ContactsContract.Groups.GROUP_IS_READ_ONLY + " = 0",null, ContactsContract.Groups.TITLE);
adapter = new SimpleCursorAdapter(this, R.layout.contact_group_item, mCursor, new String[] {
ContactsContract.Groups.TITLE,
ContactsContract.Groups._ID,
ContactsContract.Groups.ACCOUNT_NAME,
ContactsContract.Groups.ACCOUNT_TYPE,
ContactsContract.Groups.AUTO_ADD,
ContactsContract.Groups.GROUP_IS_READ_ONLY,
ContactsContract.Groups.GROUP_VISIBLE,
ContactsContract.Groups.SOURCE_ID,
ContactsContract.Groups.NOTES},
new int[] {
R.id.text1,
R.id.text2,R.id.text3, R.id.text4, R.id.text5, R.id.text6, R.id.text7, R.id.text8, R.id.text9}, SimpleCursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);
lvGroups.setAdapter(adapter);
lvGroups.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Cursor cursor = adapter.getCursor();
cursor.moveToPosition(position);
int groupId = cursor.getInt(cursor.getColumnIndex(ContactsContract.Groups._ID));
ContentValues contentValues = new ContentValues();
contentValues.put(ContactsContract.Groups.NOTES,"My test Notes");
getContentResolver().update(ContactsContract.Groups.CONTENT_URI, contentValues, ContactsContract.Groups._ID + " = " + groupId, null);
adapter.notifyDataSetChanged();
}
});
}
}
The NOTES field is a String, it looks like you're trying to set a JSON object to it.
Check if this is working for you:
if (notes!=null && notes.size()>0) {
op = op.withValue(ContactsContract.Groups.NOTES, "TEST STRING!");
}
If so, you'll need to extract the actual string you need from the JSON object, that would depend on the format of your JSON.
I try to make a simple app for read sms from my smartphone,
I run the code but and but anythings shows in my application
I try to debug the code I found this variable cur cannot be found
what is the problem here ?
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
private static final int request_permission = 123;
#RequiresApi(api = Build.VERSION_CODES.M)
public void ButtonLoad(View view) {
if((int) Build.VERSION.SDK_INT >=23){
if(ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_SMS)!= PackageManager.PERMISSION_GRANTED){
if(!shouldShowRequestPermissionRationale(Manifest.permission.READ_SMS)){
requestPermissions( new String[]{Manifest.permission.READ_SMS},request_permission);
}
return;
}
}
LoadInboxMassges();
}
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
switch (requestCode){
case request_permission:
if (grantResults[0]==PackageManager.PERMISSION_GRANTED){
LoadInboxMassges();
}else {
//permission_Denied
}
}
}
void LoadInboxMassges(){
try {
String sms = "";
Uri uriSMSURI = Uri.parse("content://sms/inbox");
Cursor cur = getContentResolver().query(uriSMSURI, null,null, null, null);
cur.moveToPosition(0);
while (cur.moveToNext()) {
sms += "From : " + cur.getString(cur.getColumnIndex("adress")) + " : " + cur.getString(cur.getColumnIndex("body")) + "\n";
TextView txtDisplay = (TextView) findViewById(R.id.txtv);
txtDisplay.setText(sms);
}
}catch (Exception ex)
{
}
}
1 remove this line cur.moveToPosition(0);
2 Change the word "adress" of this line:
sms += "From : " + cur.getString(cur.getColumnIndex("adress")) + " : " + cur.getString(cur.getColumnIndex("body")) + "\n";
to "address".
Other suggestions:
There are some other errors or something improper in your code, such as:
1 Reading sms in your inbox may spend a long time. That may crash your app.
2 Your txtDisplay should be placed out of the loop body.
3 You should call cur.close(); after cur is in the end.
In your LoadInboxMassges() method
remove the code cur.moveToPosition(0);
change in the following manner
if (cursor != null) {
while (cursor.moveToNext()) {
// read your cursor here
}
I'm having a problem with extracting phone numbers of some people in my contact list.
First I show all the contacts in a listview:
String[] projection = new String[] {
ContactsContract.Contacts._ID,
ContactsContract.CommonDataKinds.Phone.CONTACT_ID,
ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME,
ContactsContract.CommonDataKinds.Phone.NUMBER
};
mCursor = mContext.getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
projection, ContactsContract.CommonDataKinds.Phone.CONTACT_ID + "=?", new String[] {mContactId}, null);
When clicking on an item, this is how I fetch the contact_id:
#Override
public void onListItemClick(ListView l, View v, int position, long id) {
Cursor currentCursor = mContactsAdapter.getCursor();
if (currentCursor != null) {
notifyOnContactSelectedListeners(String.valueOf(id));
}
}
Then I create a new fragment, and while loading it I query for the contact's phone & display name:
if (cursor != null && cursor.getCount() > 0) {
cursor.moveToFirst();
String firstName = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
String number = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
}
So for some people that has a phone, I get the phone number this way and that's ok.
But for some people I can't get the phone number this way - but they do have phone number in the default's phone contacts book.
What went wrong?
I had a similar difficulty. I discovered that the numbers that I was unable to receive had all been imported from my linked Facebook account. You will be able to detect that the contact exists, and indeed that they have a phone number. However, when you try to retrieve said number with a SQL query the result returned will be null.
It transpired that Facebook restrict access to their contacts for security reasons. I am yet to find another provider (e.g. LinkedIn, Google) which hides phone numbers.
Further reading: Cannot find Facebook contacts in RawContacts
try this may it useful for you
public class Contact extends Activity implements OnItemClickListener{
private static final int PICK_CONTACT = 0;
Cursor c;
Cursor cursor,phones,emails,address;
String id,phoneNo,name;
String[] from;
int[] to;
ListView lv;
Cursor cur,pCur;
List<String> list1 = new ArrayList<String>();
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.contact);
lv = (ListView)findViewById(R.id.contactlist);
displayContacts();
lv.setAdapter(new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1, list1));
lv.setOnItemClickListener(this);
}
private void displayContacts() {
ContentResolver cr = getContentResolver();
cur = cr.query(ContactsContract.Contacts.CONTENT_URI,
null, null, null, null);
if (cur.getCount() > 0) {
while (cur.moveToNext()) {
id = cur.getString(cur.getColumnIndex(ContactsContract.Contacts._ID));
name = cur.getString(cur.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));
if (Integer.parseInt(cur.getString(
cur.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER))) > 0) {
pCur = cr.query(
ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
null,
ContactsContract.CommonDataKinds.Phone.CONTACT_ID +" = ?",
new String[]{id}, null);
while (pCur.moveToNext()) {
phoneNo = pCur.getString(pCur.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
// setContact(name,phoneNo);
System.out.println("name"+name+"ph no"+phoneNo);
list1.add(name+"\n"+phoneNo);
// Toast.makeText(this, "Name: " + name + ", Phone No: " + phoneNo, Toast.LENGTH_SHORT).show();
}
pCur.close();
}
}
}
}
#Override
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
// TODO Auto-generated method stub
String s = lv.getItemAtPosition(arg2).toString();
Log.i("my msg", s.substring(0, s.indexOf("\n")));
Toast.makeText(this, s.substring(s.indexOf("\n")+1,s.length() ),1 ).show();
}
}
I received null in some contacts.
I verified my code to find out that when querying phone numbers I was using ContactsContract.CommonDataKinds.Phone.NORMALIZED_NUMBER then I changed to ContactsContract.CommonDataKinds.Phone.NUMBER that according to android docs it says.
The phone number as the user entered it.
and the code worked well.
I installed the following code on my Android 2.2 phone and the sender's name shows as labuser for some messages when it is actually something else :-
public class SMSReaderActivity extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
ListView myListView = (ListView) findViewById(R.id.myListView);
final ArrayList<String> smses = new ArrayList<String>();
final ArrayAdapter<String> aa = new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1, smses);
myListView.setAdapter(aa);
Context context = getApplicationContext();
Cursor cursor = context.getContentResolver().query(
Uri.parse("content://sms/inbox"),
new String[] { "address", "person", "date", "body" }, null,
null, "date desc");
cursor.moveToFirst();
int count = cursor.getCount();
for (int j = 0; j < count; j++) {
String msg = cursor.getString(0) + ", " + cursor.getString(1)
+ ", " + cursor.getLong(2) + ", " + cursor.getString(3);
Log.w("SMS", "Read SMS:" + msg);
if (cursor.getString(3).indexOf("rbs") >= 0) {
smses.add(msg);
Log.w("SMS", "Added");
}
cursor.moveToNext();
}
cursor.close();
aa.notifyDataSetChanged();
}
labuser is not an a/c on my development machine and this happens with only matching smses. I cannot figure out the source of this.
Thanks
Himanshu
Giving it the READ_CONTACTS permission fixed it. That my app, reading SMS's without appropriate permissions, could screw up the default one was strange.
this is is the code i have but everytime i click on the contact it force closes. and is there a code so that when i get the contact it adds it into a text view?
public static final String TAG = "ContactManager";
private Button mAddAccountButton;
private ListView mContactList;
private boolean mShowInvisible;
private CheckBox mShowInvisibleControl;
/**
* Called when the activity is first created. Responsible for initializing the UI.
*/
#Override
public void onCreate(Bundle savedInstanceState)
{
Log.v(TAG, "Activity State: onCreate()");
super.onCreate(savedInstanceState);
setContentView(R.layout.main2);
// Obtain handles to UI objects
mAddAccountButton = (Button) findViewById(R.id.AddContact);
mContactList = (ListView) findViewById(R.id.ContactList);
mShowInvisibleControl = (CheckBox) findViewById(R.id.ShowInvisible);
// Initialize class properties
mShowInvisible = false;
mShowInvisibleControl.setChecked(mShowInvisible);
// Register handler for UI elements
mAddAccountButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Log.d(TAG, "mAddAccountButton clicked");
launchContactAdder();
}
});
mShowInvisibleControl.setOnCheckedChangeListener(new OnCheckedChangeListener() {
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
Log.d(TAG, "mShowInvisibleControl changed: " + isChecked);
mShowInvisible = isChecked;
populateContactList();
}
});
// Populate the contact list
populateContactList();
}
/**
* Populate the contact list based on account currently selected in the account spinner.
*/
private void populateContactList() {
// Build adapter with contact entries
Cursor cursor = getContacts();
String[] fields = new String[] {
ContactsContract.Data.DISPLAY_NAME
};
SimpleCursorAdapter adapter = new SimpleCursorAdapter(this, R.layout.main, cursor,
fields, new int[] {R.id.TextView01});
mContactList.setAdapter(adapter);
}
/**
* Obtains the contact list for the currently selected account.
*
* #return A cursor for for accessing the contact list.
*/
private Cursor getContacts()
{
// Run query
Uri uri = ContactsContract.Contacts.CONTENT_URI;
String[] projection = new String[] {
ContactsContract.Contacts._ID,
ContactsContract.Contacts.DISPLAY_NAME
};
String selection = ContactsContract.Contacts.IN_VISIBLE_GROUP + " = '" +
(mShowInvisible ? "0" : "1") + "'";
String[] selectionArgs = null;
String sortOrder = ContactsContract.Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC";
return managedQuery(uri, projection, selection, selectionArgs, sortOrder);
}
/**
* Launches the ContactAdder activity to add a new contact to the selected account.
*/
protected void launchContactAdder() {
Intent i = new Intent(this,Class1.class);
startActivity(i);
}
}
based on my experience with the contacts list, you need to design your query based on what is available. In 1.6 there was the simplicity of one table with all the information. However; with the dawn of 2.0, they introduced two tables. Where you get the ID from one table and the query based on this ID to find the phone number. To illustrate this here is a piece of sample code that worked for me, although i'm having some minor problems where some contacts won't return a phone number 2/70 although all 70 users have an ID and Phone number. I hope it helps:
// look up contact via name
String name = contacts.getItem(arg1);
Uri lookup = Uri.withAppendedPath(
ContactsContract.Contacts.CONTENT_FILTER_URI, name);
// look up id
Cursor c = getContentResolver().query(lookup, null, null, null, null);
String id = null;
int id_index = c.getColumnIndexOrThrow(ContactsContract.Contacts._ID);
if (c.moveToFirst())
id = c.getString(id_index);
else
Toast.makeText(getApplicationContext(), "Friend not found",
Toast.LENGTH_SHORT).show();
c.close();
// use id if not null, to find contact's phone number / display name
if (id != null) {
String where = ContactsContract.Data.CONTACT_ID + " = " + id
+ " AND " + ContactsContract.Data.MIMETYPE + " = '"
+ ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE
+ "'";
c = getContentResolver().query(ContactsContract.Data.CONTENT_URI,
null, where, null, null);
c.moveToFirst();
int iname = c
.getColumnIndexOrThrow(ContactsContract.Contacts.DISPLAY_NAME);
int iphone = c
.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Phone.NUMBER);
if (c.getCount() > 0) {
_friend.setName(c.getString(iname));
_friend.setPhone(c.getString(iphone));
If you have any further questions, please don't hesitate to ask, I'll do my best to answer them. For what I can tell without a log cat is that you are attempting a look up of the phone number the proper table structure for the query. If you try to access information from a query that returned 0 rows, then you'll get an exception. Please read that error and display it.
You have to use for all Email, Phone Numbers, Web-Address etc.
Example:
Linkify.addLinks(textView, Linkify.WEB_URLS);
Parameter: textview which you are adding string
Which thing you want to track email,phone or web
For more details:
http://developer.android.com/reference/android/text/util/Linkify.html
Note: for this you no need to implement any onClick etc. Linkif automatically manage it.