0

I have a ContentObserver listening content://sms/inbox. When I send long SMS message from one Android emulator to another Android emulator, this ContentObserver fires multiply (depending on the number of short sms messages in the long sms message). I need to concatenate short messages in one long message, but I have no a feature to decide were these messages sent as parts of one long message or they are independent succesive short messages. It seems available cursor columns does not contain such a feature at all:

0 = "_id"
1 = "thread_id"
2 = "address"
3 = "person"
4 = "date"
5 = "date_sent"
6 = "protocol"
7 = "read"
8 = "status"
9 = "type"
10 = "reply_path_present"
11 = "subject"
12 = "body"
13 = "service_center"
14 = "locked"
15 = "sub_id"
16 = "error_code"
17 = "creator"
18 = "seen"

As I know there is a way to do desired concatenation thru receiver and "pdus". Is it the only way to proceed?

P.S. I have found that real (not emulator) Android SMS client does not keep a long message as series of short messages. It concatenates short messages in storeMessage method and saves them as a whole long message in database. So the question is why Android emulator SMS client is differ from the real one!?

UPDATE: SmsObserverclass:

public class SMSObserver1 extends ContentObserver {
    private Context context;
    private SmsListener listener;

    public SMSObserver(Context context, Handler handler, SmsListener listener) {
        super(handler);
        this.context = context;
        this.listener = listener;
    }

    @Override
    public void onChange(boolean selfChange) {
        super.onChange(selfChange);
        Uri mUri = Uri.parse("content://sms");
        Cursor mCursor = context.getContentResolver().query(mUri, null, null, null, null);
        if (mCursor != null && mCursor.moveToNext()) {
            SmsEntity entity = null;
            int type = mCursor.getInt(mCursor.getColumnIndex("type"));//now we need to decide SMS message is sent or received
            if (type == 1) //it's received SMS
                entity = getSMS(true);
            else if (type == 2) //it's sent SMS
                entity = getSMS(false);
            mCursor.close();
            if (entity != null)
                listener.addSms(entity);
        }
    }

    private SmsEntity getSMS(boolean isIncoming) {
        SmsEntity entity = null;
        Uri uri = Uri.parse(isIncoming ? "content://sms/inbox" : "content://sms/sent");
        Cursor cursor = context.getContentResolver().query(uri, null,null, null, null);
        if (cursor != null && cursor.moveToNext()) {
            entity = printSms(cursor, isIncoming);
            cursor.close();
        }
        return entity;
    }

    private SmsEntity printSms(Cursor cursor, boolean isIncoming){
        int type = cursor.getInt(cursor.getColumnIndex("type"));
        long msg_id= cursor.getLong(cursor.getColumnIndex("_id"));
        String phone = cursor.getString(cursor.getColumnIndex("address"));
        long dateVal = cursor.getLong(cursor.getColumnIndex("date"));
        String body = cursor.getString(cursor.getColumnIndex("body"));
        Date date = new Date(dateVal);

        String str = (isIncoming ? "Received" : "Sent") + " SMS: \n phone is: " + phone;
        str +="\n SMS type is: " + type;
        str +="\n SMS time stamp is:" + date;
        str +="\n SMS body is: " + body;
        str +="\n id is : " + msg_id;
        Log.v("Debug", str);

        return new SmsEntity(msg_id, dateVal, true, isIncoming, phone, body);
    }
}

Registering/unregistering happens in onResume/onPause callbacks of Fragment:

@Override
public void onPause() {
    super.onPause();
    unregisterContentObserver();
}

public void unregisterContentObserver() {
    if (mSmsObserver != null) {
        try {
            getActivity().getContentResolver().unregisterContentObserver(mSmsObserver);
        } catch (IllegalStateException ise) {
            Timber.w(ise.getMessage());
        } finally {
            mSmsObserver = null;
        }
    }
}

@Override
public void onResume() {
    super.onResume();
    registerContentObserver();
}

private void registerContentObserver() {
    mSmsObserver = new SMSObserver(getActivity(), new Handler(),this);
    getActivity().getContentResolver().registerContentObserver(Uri.parse("content://sms/inbox"), true, mSmsObserver);//To track an incoming SMS only
}
isabsent
  • 3,683
  • 3
  • 25
  • 46
  • Are you sure you're correctly interpreting what you're seeing? Incoming multipart SMS should always be stored in a single record. As you mention, there's really no other way to group or collect them after writing. Please post your `ContentObserver`, and the code for its registration. – Mike M. Nov 14 '18 at 16:38
  • Please post your `registerContentObserver()` call. – Mike M. Nov 15 '18 at 02:52
  • I have updateted my question. I would like to stress the problem exists on **Android emulator SMS client only**. I have posted correspondent issue to Google bug tracker https://issuetracker.google.com/issues/119319859 – isabsent Nov 15 '18 at 03:10
  • Yeah, I noticed you'd mentioned that. I'm trying to reconcile your description with what I believe should be happening. However, things have changed, apparently. That is, previously, registering on `content://sms/inbox` didn't work at all. You'd have to register on `content://sms`, and sort out what actually changed in `onChange()`. Which API levels are you testing this on? Both emulator and devices. – Mike M. Nov 15 '18 at 03:20
  • Also, as a debugging tip, assuming you're testing on API level 16 or above, override `onChange(boolean selfChange, Uri uri)`, and see what `uri.toString()` is for each time it's firing unexpectedly. – Mike M. Nov 15 '18 at 03:23
  • The problem is not in `Uri`to listen changes. Try to send **long** SMS (more than 160 letters) from one Android emulator to another one and you will see a problem like http://issuetracker.google.com/issues/119319859 This problem doesn't exist if you send the same **long** SMS from menu item "Phone" placed under "..." menu to the right side of Android emulator. I have checked API 24, 25, 26. – isabsent Nov 15 '18 at 06:23
  • Yeah, you've left out a _lot_ of information here that I only saw after I noticed, and was finally able to bring up, that issue tracker link. Regardless, knowing what `Uri`s are being changed unexpectedly would at least give a better idea of what's actually happening on the emulator. However, I don't have access to my dev machine, atm, and I don't wanna try to debug this remotely through comments, so if I remember, I might have a look when I get back to my machine. If this is indeed an emulator bug, all I could do is confirm it anyway, and you'd still have to wait for a response to your issue. – Mike M. Nov 15 '18 at 06:31
  • Thanks for your consideration. I suppose Google will answer it was not intended to send SMS from one emulator to another, because there is an opportunity to send SMS to emulator from it's own "..." menu. – isabsent Nov 15 '18 at 06:48
  • Nah, I'd say that definitely should work, if that is the problem. It's been a while since I've done emulator-to-emulator tests, but I don't ever recall having this issue. It's been so long, though, that I might've been using older versions than you're currently testing. I'll make a note to do some tests, when I'm able. It might be a day or two, but I'll let ya know what I find out. And hopefully you'll get some official word on your issue, too, in the meantime. – Mike M. Nov 15 '18 at 06:56
  • Hey, there. Sorry I didn't get back to you until now, but I was finally able to test this, and you're absolutely correct. That's definitely an emulator bug. In the particular case you show in your issue, it's because it chokes on multipart messages. If you were to send 161 "a"s, you'll get garbage, whereas 160 "a"s works just fine. That's not the only issue with emulator SMS that I've discovered just since your question. Certain characters in even really short messages cause garbage, too, and data SMS just flat out doesn't work. – Mike M. Nov 24 '18 at 04:11
  • Seems like they're not very interested in getting these issues fixed, and considering the new Play Store policy disallowing most apps from using SMS anymore, I doubt they ever will. In case you're interested, here's the issue where I found out about the short message glitch: https://issuetracker.google.com/issues/37085791. – Mike M. Nov 24 '18 at 04:11
  • Thanks for the verification. Why do you think they "considering the new Play Store policy disallowing most apps from using SMS anymore"? I didn't see announcement about it. – isabsent Nov 24 '18 at 11:03
  • Yeah, they're going to prohibit most apps from accessing SMS and the call logs, unless it's the app's main functionality. I'm surprised you haven't heard about it yet. It's been pretty big news in the Android world, and has got a lot of developers pretty upset. [Here's a post](https://stackoverflow.com/q/53405467) that has the whole email they sent out. Mind you, this is only for apps distributed through the Play Store. They can't really do anything about apps offered elsewhere. – Mike M. Nov 24 '18 at 18:10
  • Wow! Thanks for this info! I had completely lost this policy update! By the way, do you have any ideas on this https://stackoverflow.com/questions/53424290/how-to-restrict-contentobserver-to-monitor-incoming-calls-from-particular-phone ? – isabsent Nov 25 '18 at 03:26
  • Yeah, I saw that question when you posted it. I did some research then, and I don't think it's possible. You can't get too specific with the URI, for some reason, when setting Observers. I've not dug through the source code to find out why, exactly, but it's the same way for the SMS Provider, too. You can only observe on the base URI. Seems silly to me, given that Google seems to frown upon apps getting too many broadcasts, system notifications, etc. You'd think they'd design it so you could observe at that granularity. – Mike M. Nov 25 '18 at 03:40

0 Answers0