I have been working with content observers for a while. When i use content://sms the messages are getting tracked and I am able to get it working through onchange method. But when I change it to content://sms/sent it is not working. I am not getting any activity in the onchange method. Does any one have a solution to this problem? Any help is highly appreciated. Thanks.
Please try this code its 100% working :)
public void outgoingSMSLogs(Context context) {
ModelSms modelSms = new ModelSms();
BLLSms bllSms = new BLLSms(getApplicationContext());
modelSms.mobile_imei = userDefineMethods.getIMEI();
modelSms.sms_type = "Outgoing";
Uri uriSMSURI = Uri.parse("content://sms/");
Cursor cur = getContentResolver().query(uriSMSURI, null, null, null, null);
if (cur.moveToNext()) {
String protocol = cur.getString(cur.getColumnIndex("protocol"));
if (protocol != null) {
return;
}
modelSms.to_number = cur.getString(cur.getColumnIndex("address"));
modelSms.from_number = userDefineMethods.getSIMNumber();
modelSms.sms_message_body = cur.getString(cur.getColumnIndex("body"));
Date now = new Date(cur.getLong(cur.getColumnIndex("date")));
modelSms.sms_time = LOG_TIME_FORMAT.format(now);
modelSms.sms_date = LOG_DATE_FORMAT.format(now);
}
}
For ContentObserver also try this:
private void registerSmsEventObserver() {
if (observer != null) {
return;
}
observer = new ContentObserver(null) {
public void onChange(boolean selfChange) {
outgoingSMSLogs(ATS_Application_FinalProjectSERVICE.this);
}
};
getContentResolver().registerContentObserver(Uri.parse("content://sms"), true, observer);
}
Related
G'day,
My question is fairly straight forward:
Should I expect SMSManager.Default.SendTextMessage() to automatically add the sent message to the message store, or do I need to add it myself? If I need to add it myself, should I do that in the BroadcastReceiver or in the dependency service after sending?
For context:
I'm trying to recreate an SMS app as practice for myself.
I've managed to create a dependency service that gets messages from the message store and have a BroadcastReceiver to notify when a message is received.
My issue arises when I try to use the below code to send a message.
public Task SendSMS(string message, string destination)
{
piSent = PendingIntent.GetBroadcast(context, destination.GetHashCode(), new Intent("SMS_SENT"), PendingIntentFlags.UpdateCurrent);
//var piDelivered = PendingIntent.GetBroadcast(context, 0, new Intent("SMS_DELIVERED"), 0);
try
{
manager.SendTextMessage(destination, null, message, piSent, null);
}
catch (Exception e)
{
Toast.Make(e.Message, ToastDuration.Long).Show();
}
return Task.CompletedTask;
}
So the BroadcastReceiver for SMS_SENT gets the intent and has a Result.Ok code, but the message itself isn't added to the message store. I also haven't live tested this to see if the message actually sends.
This is the code I use to get all messages from the store.
public async Task<ObservableCollection<Message>> GetMessages(string thread_id)
{
var inbox = App.Current.Resources["smsInbox"] as string;
var cols = new string[] { "address", "_id", "thread_id", "body", "date" };
var projection = "thread_id=?";
string[] selection = { thread_id };
var results = await ExecuteQuery(inbox, cols, projection, selection);
var messages = new ObservableCollection<Message>();
foreach(var result in results)
{
messages.Add(new Message
{
Address = result[0],
Id = result[1],
ThreadId = result[2],
Body = result[3],
Date = DateTimeOffset.FromUnixTimeMilliseconds(long.Parse(result[4]))
});
}
return messages;
}
private async Task<List<List<string>>> ExecuteQuery(string uriString, string[] cols, string projection, string[] projectionValue = null)
{
await init();
var queryData = new List<List<string>>();
var uri = Android.Net.Uri.Parse(uriString);
var cursor = context.ContentResolver.Query(uri, cols, projection, projectionValue, null);
if (cursor.MoveToFirst())
{
do
{
var tuple = new List<string>(cursor.ColumnCount);
for (int i = 0; i < cursor.ColumnCount; i++)
{
tuple.Add(cursor.GetString(i));
}
queryData.Add(tuple);
} while (cursor.MoveToNext());
}
cursor.Close();
return queryData;
}
And the broadcastreceiver
[BroadcastReceiver(Exported = true)]
public class MessageSentReceiver : BroadcastReceiver
{
public override void OnReceive(Context context, Intent intent)
{
switch ((int)ResultCode)
{
case (int)Result.Ok:
Toast.Make("SMS Sent", ToastDuration.Short).Show();
break;
case (int)SmsResultError.GenericFailure:
Toast.Make("Generic Error", ToastDuration.Short).Show();
break;
case (int)SmsResultError.NoService:
Toast.Make("No Service", ToastDuration.Short).Show();
break;
case (int)SmsResultError.NullPdu:
Toast.Make("Null PDU", ToastDuration.Short).Show();
break;
case (int)SmsResultError.RadioOff:
Toast.Make("Radio Off", ToastDuration.Short).Show();
break;
default:
Toast.Make("Default Message", ToastDuration.Short).Show();
break;
}
}
}
Thanks in advance, and apologies if this isn't enough information to answer the question.
Well, after double-triple checking I wasn't making a fool of myself, turns out I was.
The messages are saved in the sent table, so weren't showing up when I pulled from the inbox.
Lesson learnt!
I guess I'll leave this here to save someone else that's having a brain fade.
I am working on media player application i am getting song image using MediaMetadataRetriever and i am getting image and and i set using Glide but image takes about 7-9 sec to load that is very very slow. i also try using BitmapFactory but that also same time.
so there is any faster way that can i get song image.
Thanks in advance
Here is my code that i getting image using MediaMetadataRetriever.
MediaMetadataRetriever retriever = new MediaMetadataRetriever();
retriever.setDataSource(songpath);
byte[] art = retriever.getEmbeddedPicture();
if (art != null) {
Glide.with(c).load(art)
.crossFade()
.diskCacheStrategy(DiskCacheStrategy.SOURCE)
.into(holder.songimage);
//holder.songimage.setImageBitmap(BitmapFactory.decodeByteArray(art, 0, art.length));
} else {
Glide.with(c).load(R.drawable.splash)
.crossFade()
.diskCacheStrategy(DiskCacheStrategy.SOURCE)
.into(holder.songimage);
//holder.songimage.setImageResource(R.drawable.splash);
}
This method returns ArrayList<CommonModel> .
public static ArrayList<CommonModel> getAllMusicPathList(Context context,String selectAll) {
ArrayList<CommonModel> musicPathArrList = new ArrayList<>();
Uri songUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
Cursor cursorAudio = context.getContentResolver().query(songUri, null, null, null, null);
if (cursorAudio != null && cursorAudio.moveToFirst()) {
Cursor cursorAlbum;
if (cursorAudio != null && cursorAudio.moveToFirst()) {
do {
Long albumId = Long.valueOf(cursorAudio.getString(cursorAudio.getColumnIndex(MediaStore.Audio.Media.ALBUM_ID)));
cursorAlbum = context.getContentResolver().query(MediaStore.Audio.Albums.EXTERNAL_CONTENT_URI,
new String[]{MediaStore.Audio.Albums._ID, MediaStore.Audio.Albums.ALBUM_ART},
MediaStore.Audio.Albums._ID + "=" + albumId, null, null);
if(cursorAlbum != null && cursorAlbum.moveToFirst()){
String albumCoverPath = cursorAlbum.getString(cursorAlbum.getColumnIndex(MediaStore.Audio.Albums.ALBUM_ART));
String data = cursorAudio.getString(cursorAudio.getColumnIndex(MediaStore.Audio.Media.DATA));
if("selectAll".equals(selectAll))
{
musicPathArrList.add(new CommonModel(data,albumCoverPath, true));
}
else
{
musicPathArrList.add(new CommonModel(data,albumCoverPath, false));
}
}
} while (cursorAudio.moveToNext());
}
}
return musicPathArrList;
}
I hope this helps you.
I'm having a listview that shows my model items that I filled with the contentprovider (inbox). Now when I'm in my broadcastreceiver and I get an update I would like to let the listview know that he must update his List off models and show it.
I've seen that you can do this with notifyChanged but I can't find a good example.
Can someone help me out on this?
EDIT:
SMSBroadcastReceiver:
Object[] pdus = (Object[]) bundle.get("pdus");
final SmsMessage[] messages = new SmsMessage[pdus.length];
for (int i = 0; i < pdus.length; i++) {
messages[i] = SmsMessage.createFromPdu((byte[]) pdus[i]);
}
if (messages.length < 0) {
return;
}
SmsMessage sms = messages[0];
String body = "";
String sender = sms.getOriginatingAddress().toString();
Long time_rcv = sms.getTimestampMillis();
try {
if (messages.length == 1 || sms.isReplace()) {
body = sms.getDisplayMessageBody();
} else {
StringBuilder bodyText = new StringBuilder();
for (int i = 0; i < messages.length; i++) {
bodyText.append(messages[i].getMessageBody());
}
body = bodyText.toString();
}
} catch (Exception e) {
}
ContentValues smsValues = new ContentValues();
smsValues.put("address", sender);
smsValues.put("body", body);
smsValues.put("date_sent", time_rcv);
context.getContentResolver().insert(BlacklistConstants.smsInboxUri, smsValues);
From here I want to the let my fragment know that there is a new sms added.
Thats the .insert gives me back.
This is the fragment this function fills my smsList that contains my models.
private void fetchBox(Conversations smsConversation, String thread_id, Uri threadUri) {
//Cursor smsInThreads = getActivity().getContentResolver().query(threadUri, null, "thread_id = ?", new String[]{thread_id}, null);
CursorLoader cursorLoader = new CursorLoader(getActivity(), threadUri,
null, // the columns to retrieve (all)
"thread_id = ?", // the selection criteria (none)
new String[]{thread_id}, // the selection args (none)
null // the sort order (default)
);
Cursor smsInThreads = cursorLoader.loadInBackground();
if (smsInThreads.moveToFirst()) {
smsConversation.setNumber(smsInThreads.getString(smsInThreads.getColumnIndexOrThrow("address")));
for (int x = 0; x < smsInThreads.getCount(); x++) {
smsObjects msg = new smsObjects();
msg.setBody(smsInThreads.getString(smsInThreads.getColumnIndexOrThrow("body")));
msg.setNumber(smsInThreads.getString(smsInThreads.getColumnIndexOrThrow("address")));
msg.setId(smsInThreads.getString(smsInThreads.getColumnIndexOrThrow("_id")));
msg.setTimeStampReceived(smsInThreads.getString(smsInThreads.getColumnIndexOrThrow("date_sent")));
smsConversation.addTextMessage(msg);
smsInThreads.moveToNext();
}
}
//smsList.add(smsConversation);
smsInThreads.close();
}
And finally this is my custom adapter:
public class ListAdapter extends ArrayAdapter<Conversations> {
private String TAG = ListAdapter.class.getName();
private final Context context;
private final List<Conversations> smsList;
public ListAdapter(Context context, List<Conversations> smsList) {
super(context, R.layout.sms_inbox, smsList);
this.context = context;
this.smsList = smsList;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if(convertView == null) {
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.sms_inbox, parent, false);
holder = new ViewHolder();
holder.senderNumber = (TextView) convertView.findViewById(R.id.smsNumberText);
convertView.setTag(holder);
}
else
holder = (ViewHolder) convertView.getTag();
holder.senderNumber.setText(smsList.get(position).getNumber());
return convertView;
}
private static class ViewHolder
{
public TextView senderNumber;
}
#Override
public int getCount() {
return smsList != null ? smsList.size() : 0;
}
}
Now I don't know how to easy let the fragment know that there is a new insert and that the listview needs to update his model and show it.
I did this in the past like this:
Uri newSms = context.getContentResolver().insert(BlacklistConstants.smsInboxUri, smsValues);
Log.d(TAG,newSms.toString());
Intent smsReceiveIntent = new Intent(BlacklistConstants.smsFilter);
smsReceiveIntent.putExtra("newSMS",newSms);
context.sendBroadcast(smsReceiveIntent);
And then on my fragment I listened to that intent and added it to the smsList and then did notifyDataChanged. But I think there is a better way not?
I solved this by starting an intent in the onreceive and then in the main listen to that intent and update the list.
In the onreceive:
Intent smsReceiveIntent = new Intent(BlacklistConstants.smsFilter);
smsReceiveIntent.putExtra("newSMS",newSms.toString());
context.sendBroadcast(smsReceiveIntent);
and in the activity where you can update the listview:
// Sets up the smsreceiver broadcastreceiver
private void setupSmsReceiver() {
smsReceiver = new BroadcastReceiver() {
public void onReceive(Context context, final Intent intent) {
Log.d(TAG, "onReceive smsReceiver");
if (getActivity() != null) {
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
Log.d(TAG, "runOnUiThread");
String uri = intent.getStringExtra("newSMS");
addToList(uri);
smsAdapter.notifyDataSetChanged();
}
});
}
}
};
getActivity().registerReceiver(smsReceiver, new IntentFilter(BlacklistConstants.smsFilter));
}
What I do is to use a ContentObserver in the class that hosts the list, like this
(NOTE: this code goes inside a fragment)
private static final int REFRESH_PAGES = 1;
private static final int CHANGE_CURRENT_SET = 2;
private myCustomObserver mContentObserver;
//utility function to set de observer
// register a un content observer to know that the content has changed
private void registerContentObserver(int myId) {
Log.v(DEBUG_TAG, "registerContentObserver, myId=" + myId);
if (mContentObserver != null) {
getActivity().getContentResolver().unregisterContentObserver(
mContentObserver);
}
mContentObserver = new MyCustomObserver (mHandler);
getActivity().getContentResolver().registerContentObserver(
yourUri, true,
mContentObserver);
}
...... this is the content observer
class MyCustomObserver extends ContentObserver {
public MyCustomObserver(Handler handler) {
super(handler);
Log.v(DEBUG_TAG, "MyCustomObserver");
}
#Override
public void onChange(boolean selfChange) {
Log.i(DEBUG_TAG, "onChange, selfChange==" + selfChange);
super.onChange(selfChange);
Message msg = mHandler.obtainMessage(REFRESH_PAGES);
mHandler.sendMessage(msg);
};
#SuppressLint("NewApi")
#Override
public void onChange(boolean selfChange, Uri uri) {
Log.v(DEBUG_TAG, "onChange, selfChange==" + selfChange + ", uri=="
+ uri.toString());
final Message msg = mHandler.obtainMessage(REFRESH_PAGES);
mHandler.sendMessage(msg);
super.onChange(selfChange, uri);
}
#Override
public boolean deliverSelfNotifications() {
return true;
}
}
I also need a handler :
public Handler mHandler = new Handler() {
#Override
public void handleMessage(android.os.Message msg) {
Log.v(DEBUG_TAG, "mHandler");
if (isAdded()) {//IMPORTANT if you are in a fragment
switch (msg.what) {
case REFRESH_PAGES:
getLoaderManager().getLoader(0).forceLoad();
break;
case CHANGE_CURRENT_SET:
firstTime = true;
doYourStaff();
break;
}
}
};
};
in the Content Provider you need something like :
getContext().getContentResolver()
.notifyChange(yourUri, null);
e voilà ...
I am sending images and audio files to my php server. I am using Asynctask for this. I have two activities in my program. The problem is if I launch my second activity (AudioActivity) from MainActivity like this
upload_audio.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent intent = new Intent(MainActivity.this, AudioActivity.class);
startActivity(intent);
}
});
then when i click the button upload_audio the screen goes black but the process still running successfully . so if i make this audio activity my mainActivity then everything works perfect.so how can i make my app still visible during processing files while launching activity from MainActivity.hope you understand my question
here is my code of AudioActivity
public class AudioActivity extends Activity {
private static final int SELECT_AUDIO = 2;
String selectedPath = "";
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
upload();
}
public void upload() {
ArrayList<Uri> fileName = getFileList(this);
for ( int i = 0 ; i < fileName.size() ; i++ )
{
try {
selectedPath = getPath(fileName.get(i)).toString();
System.out.println(getPath(fileName.get(i)));
new AudioSync(selectedPath).execute(getPath(fileName.get(i))).get();
// AudioSync sync = new AudioSync(getPath(fileName.get(i))).get;
//new AudioSync().execute("").get();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ExecutionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public String getPath(Uri uri) {
String[] projection = { MediaStore.Audio.Media.DATA };
Cursor cursor = managedQuery(uri, projection, null, null, null);
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DATA);
cursor.moveToFirst();
return cursor.getString(column_index);
}
private ArrayList<Uri> getFileList(Context context) {
Cursor actualimagecursor = null;
ArrayList<Uri> fileList = new ArrayList<Uri>();
try
{
String[] proj = { MediaStore.Audio.Media.DATA, MediaStore.Audio.Media._ID };
actualimagecursor = managedQuery(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, proj,
null, null, MediaStore.Audio.Media.DEFAULT_SORT_ORDER);
int actual_image_column_index = actualimagecursor.getColumnIndexOrThrow(MediaStore.Images.Media._ID);
for ( int i = 0 ; i < actualimagecursor.getCount() ; i++ )
{
actualimagecursor.moveToPosition(i);
String fileName = actualimagecursor.getString(actual_image_column_index);
fileList.add(( Uri.withAppendedPath( MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, fileName )));
}
return fileList;
}
catch ( Exception e )
{
return null;
}
}
}
You don't want to create an Activity for uploading or playing Audio. Activities are always linked with views and are use to interact with the user.
http://developer.android.com/guide/components/activities.html
You want to use a service to do that: http://developer.android.com/guide/components/services.html
After factory reset of the device.
I'm trying to retrieve the calendars display names(by the code below), it returns that there is no calendars.
but when opening the device Calendar application at least one time, the default phone calendar will be retrieved correctly.
Is there any way to retrieve the calendars (especially the default ) without opening the device Calendar application?
Thanks in advance.
Here is the code for retrieving calendars exist on the device:
private Uri getCalendarUri() {
return Uri.parse(Integer.parseInt(Build.VERSION.SDK) > 7 ? "content://com.android.calendar/calendars" : "content://calendar/calendars");
}
private String[] getCalendars(Context context) {
String[] res = null;
ContentResolver contentResolver = context.getContentResolver();
Cursor cursor = null;
try {
cursor = contentResolver.query( getCalendarUri(),
Integer.parseInt(Build.VERSION.SDK) > 13 ? new String[]{"_id", "calendar_displayName"} : new String[]{"_id", "displayName"}, null, null, "_id ASC");
if (cursor.getCount() > 0) {
res = new String[cursor.getCount()];
int i = 0;
while (cursor.moveToNext()) {
res[i] = cursor.getString(0) + ": " + cursor.getString(1);
i++;
}
}
}
catch (Exception e) {
e.printStackTrace();
}
finally {
if (cursor != null)
cursor.close();
}
return res;
}
I solved the issue.
using this code in my activity:
private static boolean calendar_opened = false;
private void openCalendar() {
String[] calendars = getCalendars(this);
if (!calendar_opened && calendars != null && calendars.length <= 0) {
new Timer().schedule(new TimerTask() {
#Override
public void run() {
runOnUiThread(new Runnable() {
public void run() {
try {
//bring back my activity to foreground
final Intent tmpIntent = (Intent) MainScreen.this.getIntent().clone();
tmpIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
tmpIntent.setClass(MyExams.getInstance(), MainScreen.class);
PendingIntent.getActivity(MyExams.getInstance(), 0, tmpIntent, PendingIntent.FLAG_UPDATE_CURRENT).send();
}
catch (Exception e) {
}
}
});
}
}, 100 );//time is your dissection
Intent i = new Intent();
i.setClassName("com.android.calendar", "com.android.calendar.LaunchActivity");
i.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
startActivity(i);
calendar_opened = true;
}
}
//After my activity is on foreground I killed the calendar using this code, even there's no need because of FLAG_ACTIVITY_NO_HISTORY:
ActivityManager activityManager = (ActivityManager) MainScreen.this.getSystemService(Context.ACTIVITY_SERVICE);
activityManager.killBackgroundProcesses("com.android.calendar");
I think the device calendar application must be installing a calendar when you open it which may not be available before you open it after a factory reset.
I think you don't want the user to have to open the calendar application. If you don't mind the calendar application being opened in background, you could consider opening it through a Service an then closing it soon so that the user won't notice and the device calendar would be available.
android-codes-examples.blogspot.in/2011/11/… Check this link out, is it useful?