I am trying to read sms from content provider. I had following code
Uri uri = Uri.parse(SMS_URI_INBOX);
String whereClause = "address=?";
String[] whereArgs = {address};
String[] projection = new String[] { "*" };
Cursor cur = getContentResolver().query(uri, projection, whereClause,whereArgs, "date desc");
Everything was working fine unless address of various format came into picture. One type of addresses can be represented in various ways like "+9198765443210", "+91 987 65443210" , "+91 (987) 65443210", "098765443210" etc... These type of varied address formats reside in SMS Content provider as well.
Approach 1:
Initially I was converting all the address to format in which special characters are replaced by % like
+9198765443210 --> %98765443210%
+91 987 65443210 --> %987%65443210%
and then using
String whereClause = "address LIKE ?";
but failed because a case may come in which we are firing query address LIKE %98765443210% but address in SMS content provider is +91 987 65443210.
Is there something like normalized_address in android which we can use to get data from SMS Content provider?
Appending to #MikeM. comment, below piece of code helped me to get threadId using which I am making query in SMS Content Provider
//Getting thread Id
ContentResolver mContentResolver = context.getContentResolver();
Uri uriSmsURI1 = Uri.withAppendedPath(Telephony.MmsSms.CONTENT_FILTER_BYPHONE_URI, address);
String[] projection1 = {this.threadId};
Cursor c1 = dbService.query(mContentResolver, uriSmsURI1, projection1, null, null, null);
if(c1.getCount()==0) {
log.error(methodName, "Got count: "+c1.getCount()+" While looking for ThreadID");
return null;
}
String threadId = null;
while(c1.moveToNext()){
threadId = c1.getString(c1.getColumnIndexOrThrow(this.threadId));
}
c1.close();
Related
right now, I'm avoiding loading system audio for the devices and emulator I have by hardcoding them in SQLite NOT LIKE ... statements while querying the ContentResolver, but, what I have found that the location for the storage of sytem audio(like alarm tones and all the audio factory loaded) doesn't have a standard location in all android device.
So, to avoid loading all system audio, I need a way to fetch the directory where these audio are located, so far, I have gathered a data of these locations where the sytem audio might be:
"/system%",
"/storage/emulated/legacy/Ringtones/%",
"/storage/emulated/0/Ringtones%",
"/product/media/audio%"
but, since these might not be adequate, is there a way to fetch the directory path where the system audio is located in android?
Query audio files with MediaStore , then filter audio files with AudioColumns , and more specific for alarm sounds use IS_ALARM.
As you say :
I have found that the location for the storage of sytem audio doesn't have a standard location in all android device.
MediaStore is a database which holds references of the files and it is a solution to query files in different system storage locations.
You can use something like this:
String[] mProjection =
{
MediaStore.Audio.Media._ID,
MediaStore.Audio.Media.DATA, # path
MediaStore.Audio.Media.IS_ALARM,
MediaStore.Audio.Media.DURATION,
MediaStore.Audio.Media.SIZE
};
Cursor mCursor = getContentResolver().query(MediaStore.Audio.Media.INTERNAL_CONTENT_URI,
mProjection,
null,
null);
Note: for external storage use: MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
int index_data = mCursor.getColumnIndex(MediaStore.Audio.Media.DATA);
if (mCursor != null) {
while (mCursor.moveToNext()) {
// Gets the value from the column.
newData = mCursor.getString(index_data);
// Insert code here to process the retrieved data.
// end of while loop
}
} else {
// Insert code here to report an error if the cursor is null or the provider threw an exception.
}
References:
https://developer.android.com/guide/topics/providers/content-provider-basics#java
https://stackoverflow.com/a/64539937/3541319
Code to List all alarms in fragment:
override fun onAttach(context: Context) {
super.onAttach(context)
val projection = arrayOf(
MediaStore.Audio.Media.IS_ALARM,
MediaStore.Audio.Media.DISPLAY_NAME,
MediaStore.Audio.Media.DATE_ADDED
)
val audio: Uri = MediaStore.Audio.Media.INTERNAL_CONTENT_URI
val cur = context.contentResolver.query(
audio,
projection, // Which columns to return
"${MediaStore.Audio.Media.IS_ALARM}>0", // Which rows to return (all rows)
null, // Selection arguments (none)
null // Ordering
) ?: return
if (cur.moveToFirst()) {
val displayNameColumn: Int = cur.getColumnIndex(
MediaStore.Audio.Media.DISPLAY_NAME
)
val dateColumn: Int = cur.getColumnIndex(
MediaStore.Audio.Media.DATE_ADDED
)
do {
val displayName = cur.getString(displayNameColumn)
val date = cur.getString(dateColumn)
Log.i(
"Listing Alarms",
" displayName=$displayName , date=$date"
)
} while (cur.moveToNext())
}
You need to add
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
I would like to limit the amount of contacts displayed in my app. Currently it is querying my Contactscontract.Contacts DB and returning every primary display name that has a phone number. Is there a simple way to reduce this to a numerical amount (say only display 5 contacts), or to certain specified ID's?
This is what I have so far:
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
// load from the "Contacts table"
Uri contentUri = ContactsContract.Contacts.CONTENT_URI;
// no sub-selection, no sort order, simply every row
// projection says we want just the _id and the name column
return new CursorLoader(getActivity(),
contentUri,
PROJECTION,
ContactsContract.Contacts.HAS_PHONE_NUMBER + " =?", // This is selection string, were looking for records that HAS_PHONE_NUMER is 1
new String[]{"1"}, // 1 means that contact has a phone number
ContactsContract.Contacts._COUNT,
new String[] {"5"},
null);
}
Whenever I try to add new parameters in the return section, Android Studio immediately goes red saying cannot resolve constructor. Is this because the CursorLoader is not defined to receive more parameters?
I defined it earlier in my code as:
mAdapter = new SimpleCursorAdapter(context, layout, c, FROM, TO, flags);
Cheers,
Shyam
To achieve a limitation of query results, please add (string concatenate) a " LIMIT 5" to your query:
...
ContactsContract.Contacts.HAS_PHONE_NUMBER + "=? LIMIT 5" //This is selection string, were looking for records that HAS_PHONE_NUMER is 1 AND
// the result set is limited to 5 rows
new String[]{"1"},
null);
...
I have made an Android app that I am trying to port over to a blackberry 10 device. Currently, all of the functions of the app work except for one, where I try and get information about recent calls from the phone. This works fine on android, but does not seem to work on the blackberry 10 simulator I am using. Here is my code for the section:
final TextView time = (TextView) findViewById(R.id.AddNewEditTextTime);
final TextView date = (TextView) findViewById(R.id.AddNewEditTextDate);
final TextView number = (TextView) findViewById(R.id.AddNewEditTextNumber);
// fields to select.
String[] strFields = { android.provider.CallLog.Calls.NUMBER,
android.provider.CallLog.Calls.TYPE,
android.provider.CallLog.Calls.CACHED_NAME,
android.provider.CallLog.Calls.CACHED_NUMBER_TYPE,
android.provider.CallLog.Calls.DATE};
// only incoming.
String strSelection = android.provider.CallLog.Calls.TYPE + " = "
+ android.provider.CallLog.Calls.INCOMING_TYPE;
// most recent first
String strOrder = android.provider.CallLog.Calls.DATE + " DESC";
// get a cursor.
Cursor mCallCursor = getContentResolver().query(
android.provider.CallLog.Calls.CONTENT_URI, // content provider
// URI
strFields, // project (fields to get)
strSelection, // selection
null, // selection args
strOrder // sortorder.
);
if (mCallCursor.moveToFirst()) {
String a = mCallCursor.getString(mCallCursor
.getColumnIndex("date"));
String b = mCallCursor.getString(mCallCursor
.getColumnIndex("number"));
mCallCursor.close();
SimpleDateFormat dateF = new SimpleDateFormat("dd-MMM-yyyy");
SimpleDateFormat timeF = new SimpleDateFormat("HH:mm");
String dateString = dateF.format(new Date(Long
.parseLong(a)));
String timeString = timeF.format(new Date(Long
.parseLong(a)));
time.setText(timeString);
date.setText(dateString);
number.setText(b);
}
The if(mCallCursor.moveToFirst()) statement is never entered on the blackberry 10 device, but works fine on Android. Is there something I'm missing / doing wrong, or is there no way to use the android.provider functions like this on a blackberry 10 device?
Apparently accessing call log is not yet supported
This is not supported, the Android API is not hooked up to retreive this data.
Edit: Usually when there's an equivalent native API, the corresponding API in Android will be supported. The Android API almost always uses the native equivalent for its implementation. AFAIK there isn't a native call logs API.
By bbenninger, at support forums.
As I was working through the following tutorial, I came across this code :
public void onClickRetrieveStudents(View view) {
// Retrieve student records
String URL = "content://com.example.provider.College/students";
I am interested to see what kind of data this is, so I tried to go to the website http://com.example.provider.College/students to view the data, however it just gave some kind of error. Therefore my question is , is this URL some kind of xml document? what exactly is the format for this data... and how can I view it ?
I would recommend you familiarize yourself with the following documenation:
Content Providers:
http://developer.android.com/guide/topics/providers/content-providers.html
Essentially when you pass that "URL" to the ContentResolver (presumably you're doing somethign like this):
// Queries the user dictionary and returns results
mCursor = getContentResolver().query(
UserDictionary.Words.CONTENT_URI, // The content URI of the words table
mProjection, // The columns to return for each row
mSelectionClause // Selection criteria
mSelectionArgs, // Selection criteria
mSortOrder); // The sort order for the returned rows
You're asking android to resolve that URL to a ContentProvider which is set up to handle that URL. The URL is not "imaginary" so much as it's targets are Local objects and processes which exist and are defined by applications which use the ContentProvider mechanism to store and make data available to other applications.
The goal of that URL (which is converted to a URI in this case) is to specify which ContentProvider you want, and what you want from it.
ContentProviders are generally used by applications that want to manage a database and make that information available to other applications while minimizing access violations etc..
EDIT:
This code is from your tutorial. See added comments:
/// this url points to the content provider.
//The content provider uses it to
///reference a specific database which it has knowledge of
//This URI doesn't represent an
//actual FILE on your system, rather it represents a way for you to tell the content //provider what DATABASE to access and what you want from it.
String URL = "content://com.example.provider.College/students";
// This line converts yoru "URL" into a URI
Uri students = Uri.parse(URL);
/// This call returns a Cursor - a cursor is a object type which contains the results of your QUERY in an order manner. IN this case it is a set of rows, each of which has a number of columns coresponding to your query and database, which can be iterated over to pull information from the DB..
/// managedQuery takes, as an argument, the URI conversion of the URL - this is
// where you are actually calling to the contentprovider, asking it to do a query on the
// databse for some information
Cursor c = managedQuery(students, null, null, null, "name");
// This line moves to the first ROW in the cursor
if (c.moveToFirst()) {
// this does somethign as long as the while loop conditional is true.
do{
// This line creates a pop up toast message with the information stored in the columns of the row you the cursor is currently on.
Toast.makeText(this,
c.getString(c.getColumnIndex(StudentsProvider._ID)) +
", " + c.getString(c.getColumnIndex( StudentsProvider.NAME)) +
", " + c.getString(c.getColumnIndex( StudentsProvider.GRADE)),
Toast.LENGTH_SHORT).show();
} while (c.moveToNext());
}
Your question in the comments was:
"all I need is an example of this file: String URL = "content://com.example.provider.College/students"; , what would the data look like ? "
The answer to this is that you have an Sqlite Database on your phone somewhere - generally (and in this case definitely) created by the application and/or content provider you are accessing. You also know that the content resolver accepts this URI and some other information and will return you a CURSOR.
This question addresses what a cursor is.
use of cursor in android
If you read the tutorial fully you will find this code::
public class StudentsProvider extends ContentProvider {
static final String PROVIDER_NAME = "com.example.provider.College";
static final String URL = "content://" + PROVIDER_NAME + "/students";
static final Uri CONTENT_URI = Uri.parse(URL);
static final String _ID = "_id";
static final String NAME = "name";
static final String GRADE = "grade";
You will also find, in the manifest of your tutorial:
<provider android:name="StudentsProvider"
android:authorities="com.example.provider.College">
</provider>
Which is the registration of your ContentProvider for the URI at question.
You will note that your URL and the "PROVIDER_NAME" and "URL" have eerie similarities. This is because the ContentProvider is utilizing these values to identify itself as the resolver for this partiuclar URI to the android system.
You should create the files as described in the tutorial, make the sample app function, and you will be able to start understanding this more clearly.
It's not real, and it's not a web url. That is an example of a hypothetical ContentURI.
As an example, you might consult the UserDictionary like so -
// Queries the user dictionary and returns results
mCursor = getContentResolver().query(
UserDictionary.Words.CONTENT_URI, // The content URI of the words table
mProjection, // The columns to return for each row
mSelectionClause // Selection criteria
mSelectionArgs, // Selection criteria
mSortOrder); // The sort order for the returned rows
You might also create your own.
Have an android app that prints with a toast pop up, and reads out a received message with tts. I use "String origin = smsMessage[0].getOriginatingAddress();" to get the phone number of the sender.
I want to query the contacts list on the phone, so if the received number matches any contacts, it will print & read out the name of the sender instead. Otherwise, if the number is not recognised, it will default back to just printing & reading the OriginatingAddress number.
Iv'e looked at How can I query Android contact based on a phone number? - but not quite sure howto go about it.
Uri phoneUri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, Uri.encode(origin));
Cursor phonesCursor = context.getContentResolver().query(phoneUri, new String[] {PhoneLookup.DISPLAY_NAME}, null, null, null);
if(phonesCursor != null && phonesCursor.moveToFirst()) {
displayName = phonesCursor.getString(0); // this is the contact name
}//end if
Go this eventually.
That question had the answer and posted the code.
Uri phoneUri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI,
Uri.encode(mNumber));
Cursor phonesCursor = managedQuery(phoneUri, new String[] {PhoneLookup.DISPLAY_NAME}, null, null, null);
if(phonesCursor != null && phonesCursor.moveToFirst()) {
String displayName = phonesCursor.getString(0); // this is the contact name